Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Entity Framework 6 navigation collections are null instead of empty

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

like image 699
Micheal Johnson Avatar asked Sep 10 '17 13:09

Micheal Johnson


People also ask

How can I prevent a null reference exception in Entity Framework?

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.

Why do my navigation properties get null in EF Core?

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:

Why does context return null when I query an entity?

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.

How do I delete a relationship in Entity Framework?

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;


1 Answers

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.

like image 140
Federico Dipuma Avatar answered Nov 11 '22 06:11

Federico Dipuma