Reputation: 23
I'm trying to learn Entity Framework 6 code first using VS 2013.
I'm doing the exact same thing as in this question: How to eagerly load a many to many relationship with the entity framework code first?
Using the same setup
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;}
}
And the answer
var allStudents = context.Students.Include( s => s.Courses);
But when debugging I get a recursive result. Every Student contains a list of Courses and those Courses contains a list of Students, which contains Courses, that contains Students and so on....
The same thing without using the method .Include(...
var allStudents = context.Students;
I'm using this in a scaffolded MVC 5 ApiController which throws:
System.Runtime.Serialization.SerializationException
Removing Virtual
from the Models and still using .Include(...
throws:
Object graph for type 'SchoolEF.Models.Course' contains cycles and cannot be serialized if reference tracking is disabled.
I guess i have not fully understood how to do eager loading and how to use the .Include() method.
Upvotes: 2
Views: 1545
Reputation: 1267
You are using the include method correctly. EF is returning a Student object which has a Course object referenced. This course object also references the Student object so you have a loop reference.
This is how EF is designed to work, and you would get the same effect if you created your object hierarchy manually. e.g.
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);
}
From reading your post I think the problem is that you get a serialization error when trying to return the objects from asp.net mvc.
There are (at least) three ways that you could fix this.
1) Disable Lazy Loading
In your EF context setup adding this.Configuration.LazyLoadingEnabled = false;
will prevent EF from loading child properties automatically, so unless you explicitly include them they will be null
.
This not the best approach as lazy loading could be valuable in other parts of the project.
2) Set Course.Student to null
var allStudents = context.Students.Include( s => s.Courses);
foreach (Student student in allStudents)
{
student.Course.Student = null;
}
This is a bit of a hack
3) Tell you serializer how to handle reference loops
You don't mention which serializer you are using, but most should be able to handle reference loops in some way. This msdn blog shows how to do this when using Newtonsoft's JSON serializer.
Upvotes: 2
Reputation: 81503
If i'm reading your question correctly
You'll need to turn lazy loading off
this.ContextOptions.LazyLoadingEnabled = false;
in the constructor of your dbContext
that enables more granular control over what gets loaded and when using include
Upvotes: 1