显式加载N:M with Filtering

Mat*_*and 7 c# entity-framework

我试图从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; }
}
Run Code Online (Sandbox Code Playgroud)

流畅的API映射

modelBuilder.Entity<Grade>()
    .HasMany(e => e.Students)
    .WithMany(x => x.Grades)
    .Map(m => m.ToTable("StudentGrades").MapLeftKey("GradeId").MapRightKey("StudentId"));
Run Code Online (Sandbox Code Playgroud)

用法

这适用于并填充该student.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();
}
Run Code Online (Sandbox Code Playgroud)

生成的SQL如下所示:

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.
Run Code Online (Sandbox Code Playgroud)

当我运行此查询时,我得到了完整的结果.

但是,当我应用过滤并使用以下行时,它不会填充student.Grades.

context.Entry(student).Collection(x => x.Grades).Query().Where(x => x.Status == "A").Load();
Run Code Online (Sandbox Code Playgroud)

此行生成此查询:

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) AND ('A' = [Extent2].[Status])
//the "1" is parameterized in the actual hit.
Run Code Online (Sandbox Code Playgroud)

当我手动对数据库运行时,我在SQL Server中获得正确筛选的结果.问题是这不会填充student.Grades在C#对象中.

Iva*_*oev 5

MSDN文章中提到了这种技术- 在显式加载相关实体时应用过滤器部分,因此它应该得到支持和工作.奇怪的是,它适用于one-to-many关系,many-to-many具有显式链接表和2个one-to-many关联,但不适用于many-to-many隐式链接表.

我没有解释为什么(没有找到相关文档).我也没有解释为什么,但将它与急切加载其他集合的请求相结合可以解决问题:

context.Entry(student).Collection(s => s.Grades)
    .Query().Where(g => g.Status == "A")
    .Include(g => g.Students)
    .Load();
Run Code Online (Sandbox Code Playgroud)

这个的缺点(如评论中所提到的)是它还会加载很多属于加载等级的学生.

所以更好的方法是使用显式链接表和这样的关系:

模型:

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; }
}
Run Code Online (Sandbox Code Playgroud)

组态:

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();
Run Code Online (Sandbox Code Playgroud)

现在,显式加载不需要技巧,只会加载已填充的过滤相关StudentGrade实体,GradeIdStudentId填充字段,从而避免加载其他GradeStudent对象:

context.Entry(student).Collection(s => s.StudentGrades)
    .Query().Where(sg => sg.Grade.Status == "A")
    .Load();
Run Code Online (Sandbox Code Playgroud)

  • 这实际上非常有效.我抓住的单身学生可能会加载很多额外的学生而不受此影响.我想我仍然会继续使用显式实体.谢谢! (2认同)