I'm trying to write a relational database application using Entity Framework 6. I have classes analogous to:
public class Subject
{
public int ID { get; set; }
public string Name { get; set; }
public virtual ICollection<Student> Students { get; set; }
}
public class Student
{
public int ID { get; set; }
public int SubjectID { get; set; }
public string Name { get; set; }
public virtual Subject Subject { get; set; }
}
(OK this is a bad example because in reality you'd want each student to be in more than one subject but let's ignore this for now as it was the best example that I could think of.)
The problem is that, whenever there's a subject with no students, instead of subjectInstance.Students
returning an empty collection it instead returns null
. This means that I cannot call subjectInstance.Students.Add(studentInstance)
to add the first student. I instead have to add the student separately, by calling contextInstance.Students.Add(studentInstance)
after manually setting the SubjectID
field on studentInstance
. Once there's one or more students already associated with the subject, subjectInstance.Students
is no longer null and I can add further students in the expected way.
What I've already tried:
Removing virtual
from public virtual ICollection<Student> Students { get; set; }
- no change
Calling contextInstance.Entry(subjectInstance).Collection("Students").Load()
before attempting to access the collection - works but it's messy and breaks separation of concerns (the modules that work with the data shouldn't have to concern themselves with loading the data)
Calling contextInstance.Subjects.Include("Students")
at some point before creating subjectInstance
- no change
As the official documentation demonstrates, you should always initialize your collection navigation properties inside the entity constructor if you want to prevent a Null reference exception.
The reason is explained in the Loading Related Data section of the EF Core documentation. The first behavior is because EF Core currently does not support lazy loading, so normally you'll get null for navigation properties until you specifically load them via eager or explicit loading. However, the Eager loading section contains the following:
In your example, you have not given the entity a Key, therefore, the context has no handle on the entity. Therefore, when you query, the context doesn't find an object and returns null. If you want to initialize a new entity, I would recommend to give it at least a Key (usually the Id property), and then select by that key when you lookup later.
To delete the relationship, set the navigation property to null. If you are working with Entity Framework that is based on .NET 4.0, then the related end needs to be loaded before you set it to null. For example: context.Entry(course).Reference(c => c.Department).Load(); course.Department = null;
As the official documentation demonstrates, you should always initialize your collection navigation properties inside the entity constructor if you want to prevent a Null reference exception.
public Subject()
{
Students = new HashSet<Student>(); // you may also use List<Student>, but HashSet will guarantee that you are not adding the same Student mistakenly twice
}
Entity framework will fill Students
property (using a proxy) only if there is at least a student, else it will leave the property as is (null if you have not initialized it).
When the entity is not a proxy, then Entity Framework tracks its changes only when calling SaveChanges()
on the context, using its original entity state for comparison. This answer will further clarify this behavior.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With