为什么导航属性在其类为私有时不填充

本文关键字:填充 导航 属性 为什么 | 更新日期: 2023-09-27 18:31:05

我有这个简单的模型:

class Parent
{
   public int Id { get; set; }
   public virtual ICollection<Child> Children { get; set; }
}
class Child
{
   public int Id { get; set; }
   public int ParentId { get; set; }
   public virtual Parent Parent { get; set; }
}
class MyContext : DbContext
{
    public DbSet<Parent> Parents { get; set; }
    public DbSet<Child> Children { get; set; }
    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        modelBuilder.Entity<Child>().HasRequired(s => s.Parent).WithMany(s => s.Children).HasForeignKey(s => s.ParentId);
        base.OnModelCreating(modelBuilder);
    }
}

当我使用如下所示的MyContext时,我得到空引用异常child.Parent因为 null

var context = new MyContext();
var child = context.Children.First();
var parentId = child.Parent.Id;              // Parent == null

为了解决这个问题,我必须更改Parent的访问修饰符,并将Child类更改为public

为什么需要这样做?或者这只是一个错误?

为什么导航属性在其类为私有时不填充

这不是错误,您正在使用称为延迟加载的实体框架功能,要使用它,您需要满足可以在此链接中找到的一些要求。其中一个要求是您的实体类必须public 。在该链接中,你将找到有关为什么应满足这些要求的正确解释,但总而言之,你的问题是因为 EF 无法从实体创建代理类,因此不能使用延迟加载。你已经满足延迟加载的主要要求,即导航属性必须virtual,但首先必须满足 EF 创建代理类所需的要求。

作为附加资源,我建议您查看此 msdn 页面,您可以在其中找到使用 EF 加载相关实体的所有方法。

首先,要澄清一些事情:你的类不是private的,它们是internal的。不能将顶级类型(非嵌套类型)声明为专用类型(有关详细信息,请参阅 MSDN 访问修饰符)。

其次,默认情况下首先为代码启用延迟加载。正如octaviocci所提到的,如果你希望使用延迟加载,你需要将它们声明为公共:这只是要求的一部分。通过将导航属性声明为 virtual告诉 EF 你希望使用延迟加载。如果您不想,可以(应该)删除virtual关键字。然后,在获取实体时,使用 Include 方法急切地加载相关实体。

var context = new MyContext();
var child = context.Children.Include(c => c.Parent).First();
var parentId = child.Parent.Id;