【问题标题】:Entity framework 6 many to many code first eager loading gives recursive result实体框架6多对多代码优先加载给出递归结果
【发布时间】:2015-01-20 22:55:37
【问题描述】:

我正在尝试首先使用 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(... 抛出:

“SchoolEF.Models.Course”类型的对象图包含循环 如果禁用引用跟踪,则无法序列化。

我想我还没有完全理解如何进行预加载以及如何使用 .Include() 方法。

【问题讨论】:

    标签: c# entity-framework ef-code-first eager-loading


    【解决方案1】:

    您正确地使用了 include 方法。 EF 正在返回一个 Student 对象,该对象引用了一个 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);
    }
    

    通过阅读您的帖子,我认为问题是您在尝试从 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 序列化程序时如何做到这一点。

    【讨论】:

    • 很好的答案,但我必须不同意延迟加载可能是有价值的评论,就个人而言,它对人类的破坏,并导致更多的问题然后它解决了
    • 我已将 can 更新为 could。我倾向于同意你的观点,我总是禁用它,但它在某些情况下一定很有用......
    • 由于这个答案和建议的msdn blog,我发现我有两个不同的问题解决方案是禁用 LazyLoading 并将config.Formatters.JsonFormatter.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore; 插入到 WebApiConfig.cs
    【解决方案2】:

    如果我没看错你的问题

    您需要关闭延迟加载

    this.ContextOptions.LazyLoadingEnabled = false;
    

    在你的 dbContext 的构造函数中

    这可以更精细地控制加载的内容以及何时使用 include

    【讨论】:

      猜你喜欢
      • 2016-08-24
      • 1970-01-01
      • 2011-07-04
      • 1970-01-01
      • 1970-01-01
      • 2012-04-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多