繁体   English   中英

实体的动态代理/延迟加载在 ef6 中并不总是有效

[英]dynamic proxies / lazy loading for entities doesn't work all the time in ef6

我正在将 EF6 与我的 Web 应用程序一起使用,并试图阐明急切加载/延迟加载的工作原理。 从我的研究来看,如果我想要动态代理,我必须将属性标记为“虚拟”。 此外,似乎默认情况下启用了动态代理。 我没有在我的数据库上下文中禁用延迟加载或动态代理加载。 我有一个例子:

//action method which is passed in a projectId
var project = dbContext.Projects.SingleOrDefault(p => p.Id == projectId);
//inspect project by setting debug point here.


public class Project{
public Client Client{get;set;} // this has a dynamic proxy created when loading
public System System{get;set;} // this property is  just null
}

通常我必须通过以下方式解决这个问题:

dbContext.Projects.Include(p => p.System).SingleOrDefault(p => p.Id == projectId);

是什么赋予了? 有人可以为我揭开这个神秘面纱吗?

为确保启用延迟加载代理,您需要将属性声明为virtual属性,并确保未在 DbContext 上禁用延迟加载。

您可能看到的行为是由于 dbContext 已经获取到相关实体之一并将其自动关联到您请求的相关实体。

让我们以一个项目(ID#1)和一个客户(ID#1)为例

如果您执行以下操作:

using ( var context = new MyDbContext())
{
    var project = context.Projects.Single(x => x.Id == 1);
    Console.WriteLine("Has Client: " + (project.Client != null).ToString());
}

如果没有virtual你会得到“有客户端:假”。 使用virtual控制台语句将触发对数据库的第二次查询,然后返回“有客户端:真”。

现在,事情变得有趣了:

using ( var context = new MyDbContext())
{
    var tempClient = context.Clients.Single(x => x.Id == 1);

    var project = context.Projects.Single(x => x.Id == 1);
    Console.WriteLine("Has Client: " + (project.Client != null).ToString());
}

在这种情况下,我们的上下文只是加载对客户端 ID #1 的引用。 我们不做任何其他事情或将它与我们的项目引用相关联,我们只是像以前一样加载项目。 在这种情况下,输出将是“Has Client: True”,即使我们不急切加载它,并且它没有被标记为virtual 由于项目#1 有对客户#1 的引用,而客户#1 已被DbContext 跟踪,因此在我们请求项目#1 时会包含该引用。

这是使用长时间运行的 DbContexts 的结果,它可能导致应用程序中完全取决于情境的相当不可预测的行为。 您需要注意长时间运行,甚至请求有界 DbContext 实例,因为这可能导致获得不完整的数据图片。 例如,如果您有一个带有子级引用的父级,其中父级 #1 有 3 个子级。 (#1、#2 和 #3)如果您的上下文由于任何原因已加载并正在跟踪子级 #1 和 #2,并且您稍后加载父级 #1 而不急于加载子级,则该父级的 Children 集合将只列出 2 3 个子项(#1 和 #2)中的一个,这可能会给您的客户提供不完整和不准确的数据视图。 (当客户“有时”无缘无故地看到不完整的数据时,可以跟踪有趣的错误。)

通常,建议确保所有引用都标记为virtual并尽可能缩短 DbContext 的生命周期。 我建议使用一个工作单元模式,它可以被注入并且生命周期范围限定于请求,但负责为 DbContext 本身创建更严格的生命周期范围,类似于using (var context = new MyDbContext())而无需将代码绑定到 DbContext。

根据 本教程,动态代理是在以下情况下创建的:

  • POCO 类声明为具有公共访问权限。
  • POCO 类不是密封的。
  • POCO 类不是抽象的。
  • 每个导航属性都声明为公共的、虚拟的。
  • 每个集合属性都是ICollection <T>类型。
  • ProxyCreationEnabled 选项在上下文类中启用。

您的System类是否满足所有这些条件?

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM