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 序列化程序时执行此操作。