参见英文答案 >
How to manually load related entities in a N:N relationship?2个
我试图从EntityFramework中的显式加载过滤结果.
我试图从EntityFramework中的显式加载过滤结果.
当我不应用任何过滤器但是在应用过滤器后它不加载结果时,显式加载有效.
类
public partial class Student { public int StudentId { get; set; } public int CourseId { get; set; } public string Name { get; set; } public string Status { get; set; } public virtual ICollection<Grade> Grades { get; set; } } public partial class Grade { public int GradeId { get; set; } public string Value { get; set; } public string Status { get; set; } public virtual ICollection<Student> Students { get; set; } }
流畅的API映射
modelBuilder.Entity<Grade>() .HasMany(e => e.Students) .WithMany(x => x.Grades) .Map(m => m.ToTable("StudentGrades").MapLeftKey("GradeId").MapRightKey("StudentId"));
这适用于学生.Grades属性.
using (var context = new Model1()) { context.Configuration.LazyLoadingEnabled = false; var student = context.Students.Single(x => x.StudentId == 1); context.Entry(student).Collection(x => x.Grades).Load(); }
SELECT [Extent2].[GradeId] AS [GradeId],[Extent2].[Value] AS [Value],[Extent2].[Status] AS [Status] FROM [dbo].[StudentGrades] AS [Extent1] INNER JOIN [dbo].[Grades] AS [Extent2] ON [Extent1].[GradeId] = [Extent2].[GradeId] WHERE [Extent1].[StudentId] = 1 // this is parameterized in the actual hit.
当我运行此查询时,我得到了完整的结果.
但是,当我应用过滤并使用以下行时,它不会填充student.Grades.
context.Entry(student).Collection(x => x.Grades).Query().Where(x => x.Status == "A").Load();
SELECT [Extent2].[GradeId] AS [GradeId],[Extent2].[Status] AS [Status] FROM [dbo].[StudentGrades] AS [Extent1] INNER JOIN [dbo].[Grades] AS [Extent2] ON [Extent1].[GradeId] = [Extent2].[GradeId] WHERE ([Extent1].[StudentId] = 1) AND ('A' = [Extent2].[Status]) //the "1" is parameterized in the actual hit.
当我手动对数据库运行时,我在sql Server中获得正确筛选的结果.问题是这不会填充C#对象中的student.Grades.
解决方法
在明确加载相关实体部分时,MSDN Article – 应用过滤器中提到了这种技术,因此它应该得到支持和工作.奇怪的是,它适用于一对多关系,多对多具有显式链接表和2个一对多关联,但不适用于具有隐式链接表的多对多关系.
我没有解释为什么(没有找到相关文档).我也没有解释为什么,但将它与急切加载其他集合的请求相结合可以解决问题:
context.Entry(student).Collection(s => s.Grades) .Query().Where(g => g.Status == "A") .Include(g => g.Students) .Load();
这个的缺点(如评论中所提到的)是它还会加载很多属于加载等级的学生.
模型:
public partial class Student { public int StudentId { get; set; } public int CourseId { get; set; } public string Name { get; set; } public string Status { get; set; } public virtual ICollection<StudentGrade> StudentGrades { get; set; } } public partial class Grade { public int GradeId { get; set; } public string Value { get; set; } public string Status { get; set; } public virtual ICollection<StudentGrade> StudentGrades { get; set; } } public class StudentGrade { public int StudentId { get; set; } public int GradeId { get; set; } public virtual Student Student { get; set; } public virtual Grade Grade { get; set; } }
组态:
modelBuilder.Entity<StudentGrade>() .ToTable("StudentGrades") .HasKey(e => new { e.GradeId,e.StudentId }); modelBuilder.Entity<StudentGrade>() .Hasrequired(e => e.Grade) .WithMany(x => x.StudentGrades) .HasForeignKey(e => e.GradeId) .WillCascadeOnDelete(); modelBuilder.Entity<StudentGrade>() .Hasrequired(e => e.Student) .WithMany(x => x.StudentGrades) .HasForeignKey(e => e.StudentId) .WillCascadeOnDelete();
现在显式加载不需要技巧,并且将加载已填充的GradeId和StudentId字段的已过滤的相关StudentGrade实体,从而避免加载其他Grade和Student对象:
context.Entry(student).Collection(s => s.StudentGrades) .Query().Where(sg => sg.Grade.Status == "A") .Load();