实体框架6导航集合为空而不是空

时间:2017-09-10 13:25:51

标签: c# entity-framework-6

我正在尝试使用Entity Framework 6编写关系数据库应用程序。我有类似的类:

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; }
}

(好的,这是一个不好的例子,因为实际上你希望每个学生都在一个以上的学科,但现在让我们忽略它,因为这是我能想到的最好的例子。)

问题在于,只要没有学生的主题,而不是subjectInstance.Students返回空集合,它将返回null。这意味着我无法呼叫subjectInstance.Students.Add(studentInstance)添加第一个学生。我需要在contextInstance.Students.Add(studentInstance)上手动设置SubjectID字段后拨打studentInstance,单独添加学生。一旦有一个或多个学生已经与该主题相关联,subjectInstance.Students不再为空,我可以按预期方式添加更多学生。

我已尝试过的内容:

  • virtual删除public virtual ICollection<Student> Students { get; set; } - 无变更

  • 在尝试访问集合之前调用contextInstance.Entry(subjectInstance).Collection("Students").Load() - 工作但是很麻烦并且打破了关注点的分离(使用数据的模块不应该关心加载数据)

  • 在创建contextInstance.Subjects.Include("Students")之前的某个时刻致电subjectInstance - 无变更

1 个答案:

答案 0 :(得分:6)

official documentation所示,如果要阻止Null引用异常,则应始终在实体构造函数中初始化集合导航属性。

public Subject()
{
    Students = new HashSet<Student>(); // you may also use List<Student>, but HashSet will guarantee that you are not adding the same Student two times for mistake
}

实体框架仅在至少有学生的情况下填充Students属性(使用代理),否则它将保留原样(如果尚未初始化,则为null)。

当实体不是代理时,实体框架仅在使用其原始实体状态进行比较时在上下文上调用SaveChanges()时跟踪其更改。 This answer将进一步澄清这种行为。