新实体的 EF Core 延迟加载器行为

EF Core lazy loader behaviour with new entities

lazy loading without proxies 上的 EF Core 文档引用了这个例子:

public class Blog
{
    private ICollection<Post> _posts;

    public Blog()
    {
    }

    private Blog(ILazyLoader lazyLoader)
    {
        LazyLoader = lazyLoader;
    }

    private ILazyLoader LazyLoader { get; set; }

    public int Id { get; set; }
    public string Name { get; set; }

    public ICollection<Post> Posts
    {
        get => LazyLoader.Load(this, ref _posts);
        set => _posts = value;
    }
}

所以我们有一个无参数构造函数和一个惰性加载器注入构造函数。然后文档这样说:

This method doesn't require entity types to be inherited from or navigation properties to be virtual, and allows entity instances created with new to lazy-load once attached to a context.

那么这对新实例到底意味着什么?由 EF 核心创建的实体将注入延迟加载程序,但 new 实体不会。这是否意味着一旦将新项目添加到上下文中,惰性加载程序支持字段应该更新?

当涉及私有构造函数和 setters 时,

EF 在某种程度上打破了封装规则。这不是一件坏事,因为将这些私有化的真正目标是确保组织对代码的访问,而无需猜测使用哪个和使用什么,但同时 EF 将通过反射忽略这些限制。

当您 Attach 一个实体到 DbContext 时,那个 DbContext 将检查附加实体的 属性 类型它可以注入。这包括 ILazyLoader,EF 将使用私有 setter 进行连接。因此,您可以 new 建立一个新实体,一旦附加到 DbContext,它将可以访问延迟加载程序。

So what does this mean exactly for new instances? An entity created by EF core will have the lazy loader injected but a new entity will not. Does this imply that once a new item is added to the context the lazy loader backing field should get updated?

正是这个意思。请注意,在此处附加到上下文

allows entity instances created with new to lazy-load once attached to a context.

表示tracked(他们在大多数地方使用的常用术语),换句话说,任何将实体添加到上下文更改跟踪器的操作 - AttachAddUpdateRemove、将 EntityEntry.State 设置为 EntityState.Detached 以外的任何内容、通过跟踪查询等创建的实体

遗憾的是,文档并未解释所有细节,因此以下是通过实验检索到的一些附加信息:

首先,如上所述,在跟踪实体时设置延迟加载程序服务属性。但反之亦然——当实体未被跟踪时 属性 被清空,例如通过将 State 设置为 EntityState.Detached.

其次是 属性 本身的实际要求。文档最后说:

Note

The constructor parameter for the lazy-loading delegate must be called "lazyLoader". Configuration to use a different name than this is planned for a future release.

这不完全正确。

实际要求是

  • 属性 与 getter 和 setter
  • 具有任何可见性(通常 private
  • 不区分大小写名称“LazyLoader”
  • 键入 ILazyLoaderAction<object, string>

更新: OP 发现的附加要求:

  • 如果服务 属性 在基 class 中定义,getter 应该对派生 class 可见,即在至少 protected。 setter 可以是 private.

  • 属性不能用[NotMapped]属性修饰或者Ignored流畅

同时,不需要具有相应参数的“注入”构造函数。创建实体实例时,EF Core 将使用任何构造函数并设置惰性加载程序服务属性,其方式与跟踪现有实体实例时的方式相同。