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#对象中.
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实体,GradeId并StudentId填充字段,从而避免加载其他Grade和Student对象:
context.Entry(student).Collection(s => s.StudentGrades)
.Query().Where(sg => sg.Grade.Status == "A")
.Load();
Run Code Online (Sandbox Code Playgroud)