Entity framework 6 多对多代码首先预加载给出递归结果
Entity framework 6 many to many code first eager loading gives recursive result
我正在尝试使用 VS 2013 学习 Entity Framework 6 代码。
我正在做与这个问题完全相同的事情:How to eagerly load a many to many relationship with the entity framework code first?
使用相同的设置
public class Student
{
public int Id {get;set}
public string FullName {get;set;}
public virtual ICollection<Course> Courses {get;set;}
}
public class Course
{
public int Id {get;set;}
public string FullName {get;set;}
public virtual ICollection<Student> Students {get;set;}
}
答案
var allStudents = context.Students.Include( s => s.Courses);
但是在调试时我得到了一个递归结果。
每个学生都包含一个课程列表,这些课程包含一个学生列表,其中包含课程,包含学生等等....
不使用方法也是一样.Include(...
var allStudents = context.Students;
我在脚手架 MVC 5 ApiController 中使用它,它抛出:
System.Runtime.Serialization.SerializationException
从模型中删除 Virtual
并仍在使用 .Include(...
抛出:
Object graph for type 'SchoolEF.Models.Course' contains cycles
and cannot be serialized if reference tracking is disabled.
我想我还没有完全理解如何进行预先加载以及如何使用 .Include() 方法。
如果我没看错你的问题
您需要关闭延迟加载
this.ContextOptions.LazyLoadingEnabled = false;
在 dbContext 的构造函数中
可以更精细地控制加载的内容以及何时使用 include
您正确使用了 include 方法。 EF 正在 returning 一个引用了 Course 对象的 Student 对象。此课程对象还引用学生对象,因此您有一个循环引用。
这就是 EF 设计的工作方式,如果您手动创建对象层次结构,您将获得相同的效果。例如
public void ReferenceLoop_CheckAreEqual()
{
Student student = new Student();
Course course = new Course();
student.Course = course;
course.Student = student;
//This is now allowed
course.Student.Course.Student.Course;
Assert.IsTrue(Object.ReferenceEquals(course, course.Student.Course.Student.Course);
}
从阅读你的 post 我认为问题是你在尝试 return 来自 asp.net mvc.
的对象时遇到序列化错误
有(至少)三种方法可以解决这个问题。
1) 禁用延迟加载
在您的 EF 上下文设置中添加 this.Configuration.LazyLoadingEnabled = false;
将阻止 EF 自动加载子属性,因此除非您明确包含它们,否则它们将是 null
.
这不是最好的方法,因为延迟加载可能在项目的其他部分很有价值。
2) 将 Course.Student 设置为 null
var allStudents = context.Students.Include( s => s.Courses);
foreach (Student student in allStudents)
{
student.Course.Student = null;
}
这有点骇人听闻
3) 告诉你序列化器如何处理引用循环
您没有提到您使用的是哪个序列化器,但大多数序列化器应该能够以某种方式处理引用循环。 This msdn blog 展示了如何在使用 Newtonsoft 的 JSON 序列化程序时执行此操作。
我正在尝试使用 VS 2013 学习 Entity Framework 6 代码。
我正在做与这个问题完全相同的事情:How to eagerly load a many to many relationship with the entity framework code first?
使用相同的设置
public class Student
{
public int Id {get;set}
public string FullName {get;set;}
public virtual ICollection<Course> Courses {get;set;}
}
public class Course
{
public int Id {get;set;}
public string FullName {get;set;}
public virtual ICollection<Student> Students {get;set;}
}
答案
var allStudents = context.Students.Include( s => s.Courses);
但是在调试时我得到了一个递归结果。 每个学生都包含一个课程列表,这些课程包含一个学生列表,其中包含课程,包含学生等等....
不使用方法也是一样.Include(...
var allStudents = context.Students;
我在脚手架 MVC 5 ApiController 中使用它,它抛出:
System.Runtime.Serialization.SerializationException
从模型中删除 Virtual
并仍在使用 .Include(...
抛出:
Object graph for type 'SchoolEF.Models.Course' contains cycles and cannot be serialized if reference tracking is disabled.
我想我还没有完全理解如何进行预先加载以及如何使用 .Include() 方法。
如果我没看错你的问题
您需要关闭延迟加载
this.ContextOptions.LazyLoadingEnabled = false;
在 dbContext 的构造函数中
可以更精细地控制加载的内容以及何时使用 include
您正确使用了 include 方法。 EF 正在 returning 一个引用了 Course 对象的 Student 对象。此课程对象还引用学生对象,因此您有一个循环引用。
这就是 EF 设计的工作方式,如果您手动创建对象层次结构,您将获得相同的效果。例如
public void ReferenceLoop_CheckAreEqual()
{
Student student = new Student();
Course course = new Course();
student.Course = course;
course.Student = student;
//This is now allowed
course.Student.Course.Student.Course;
Assert.IsTrue(Object.ReferenceEquals(course, course.Student.Course.Student.Course);
}
从阅读你的 post 我认为问题是你在尝试 return 来自 asp.net mvc.
的对象时遇到序列化错误有(至少)三种方法可以解决这个问题。
1) 禁用延迟加载
在您的 EF 上下文设置中添加 this.Configuration.LazyLoadingEnabled = false;
将阻止 EF 自动加载子属性,因此除非您明确包含它们,否则它们将是 null
.
这不是最好的方法,因为延迟加载可能在项目的其他部分很有价值。
2) 将 Course.Student 设置为 null
var allStudents = context.Students.Include( s => s.Courses);
foreach (Student student in allStudents)
{
student.Course.Student = null;
}
这有点骇人听闻
3) 告诉你序列化器如何处理引用循环
您没有提到您使用的是哪个序列化器,但大多数序列化器应该能够以某种方式处理引用循环。 This msdn blog 展示了如何在使用 Newtonsoft 的 JSON 序列化程序时执行此操作。