【问题标题】:Entity Framework is not loading the reference and collection properties lazily实体框架没有延迟加载引用和集合属性
【发布时间】:2017-04-19 21:32:17
【问题描述】:

我有 Backpack 和 Book 实体。书籍参考背包(一对多)。 我正在创建一个背包和一堆书籍的实例。所以在这种情况下,背包里有一堆书。我将这些实体保存到数据库中。我正在验证那些已保存到数据库中。当我尝试加载背包时,它加载正常,并且除了导航属性之外的所有属性都已设置。我也在检查 LazyLoading 是否被禁用。我的导航属性有 virtual 关键字。 我不确定我做错了什么。如果我尝试使用 Include() 加载背包,它会加载书籍:

dbContext.Backpacks.Where(b=>b.Name!="").Include("Books").FirstOrDefault()

我想弄清楚为什么它不懒惰地加载书籍?我在加载这本书时遇到了同样的问题。当我加载这本书时,它没有连接背包。我看到 BackpackId 在那里。

在我的属性 getter/setter 中,我有一些将被触发的逻辑,但我不确定这会是什么问题。

【问题讨论】:

  • 你能展示你的实体吗?
  • 是否也启用了 ProxyCreation?延迟加载需要工作
  • @Sentry 我刚刚检查并启用了 ProxyCreation。我将其设置为 false,但问题仍然没有消失。
  • ProxyCreation 必须为真,而不是假。上下文是否仍然打开?您能否显示更多代码,尤其是从您创建上下文的位置直到您释放它?
  • @Sentry 我不允许在网上发布代码,因为它不仅仅是两个实体。如果你没问题,我们可以通过 Skype 与我分享我的屏幕。感谢您的帮助!

标签: c# entity-framework entity-framework-6 lazy-loading


【解决方案1】:

由于手头的信息有限,我可以看到以下对您的问题的解释。

延迟加载或代理创建被禁用

确保启用延迟加载和代理创建,如果没有后者,第一个将无法工作。

dbContext.Configuration.ProxyCreationEnabled = true;
dbContext.Configuration.LazyLoadingEnabled = true;

(详见this SO post

释放上下文后访问实体

简化的延迟加载是这样工作的:

  • 每当您从上下文中检索实体时,您实际上会获得一个自动创建的您期望的类的子类的对象,它会覆盖您的virtual 导航属性,即代理。。李>
  • 当您随后访问所述导航属性时,代理将访问数据库并在需要时加载链接的实体。

当然,这最后一步只有在实体/代理仍然附加到上下文并因此可以查询数据库以检索所述对象时才有可能。

using( var dbContext = new MyContext() )
{
    dbContext.Configuration.ProxyCreationEnabled = true;
    dbContext.Configuration.LazyLoadingEnabled = true;
    // Note: You can modify or derive from `MyContext` so that this is
    //       done automatically whenever a new `MyContext` is instantiated

    var backpack = dbContext.Backpacks.Where(b=>b.Name!="").FirstOrDefault();

    // This should work
    var firstBook = backpack.Books.FirstOrDefault();
}

// This will probably not, because the context was already disposed
var firstDrink = backpack.Drinks.FirstOrDefault();

我希望这会有所帮助,但如果没有,请随时提供更多信息

【讨论】:

  • ProxyCreation 默认启用。我虽然启用会导致 LazyLoad 问题。因此,在我的情况下,启用了 ProxyCreation 并启用了 LazyLoading。我要测试一些东西然后回来。
【解决方案2】:

经过几天的调试,终于找到了问题所在。如上所述,您必须启用 LazyLoading 和 ProxyCreating。即使启用了 LazyLoading 和 ProxyCreating,我也遇到了问题。还要确保将导航属性声明为virtual,否则 EF 将无法延迟加载实体。

所以我遇到的问题是,EF 没有创建代理,因为我的实体没有没有参数的公共或受保护构造函数。在创建没有参数的公共(在我的情况下是受保护的)构造函数后,它起作用了。

注意:没有没有参数的公共/受保护构造函数不会影响预加载。

Here is a link that explains the requirements for the LazyLoading

【讨论】:

    【解决方案3】:

    预加载是使用Include() 方法实现的,因此您使用Include("Books") 强制预加载。

    改变这个:

    dbContext.Backpacks.Where(b=>b.Name!="").Include("Books").FirstOrDefault()
    

    到这里:

    dbContext.Backpacks.Where(b=>b.Name!="").FirstOrDefault()
    

    您现在应该看到 Books 不再被急切地加载。

    参考:

    1. http://www.entityframeworktutorial.net/EntityFramework4.3/eager-loading-with-dbcontext.aspx
    2. https://msdn.microsoft.com/en-us/library/jj574232(v=vs.113).aspx

    【讨论】:

    • 我知道 Include 会急切地加载实体,我只是用 Include 对其进行了测试,看看它是否有效。如果我尝试在不使用包含的情况下加载背包,那么我不会在导航列表中获得书籍。
    • @Dilshod 您需要发布更多代码。你对问题男性的描述完全没有意义。
    【解决方案4】:

    使用 .NET Core 3.1 和 Microsoft.EntityFrameworkCore 3.1.5 必须执行的步骤...

    1) 添加Microsoft.EntityFrameworkCore.Proxies NuGet 包

    2) 将您的DbContext 配置为UseLazyLoadingProxies(在Startup.cs 中)

    public void ConfigureServices(IServiceCollection services)
    {
       ...
        services.AddDbContext<DataContext>(optionsBuilder =>
        {
            optionsBuilder
                .UseLazyLoadingProxies() // <--- You need this bit
                .UseSqlServer(Configuration.GetConnectionString("DefaultConnection"));
        });
       ...
    }
    

    3) 将所有适当的属性(您想要延迟加载的属性)标记为virtual

    public class MyEntity 
    {
        public virtual OtherEntity? { get; set; }  // Lazy loaded coz `virtual`
    
        public ICollection<OtherEntity> { get; set; }  // NOT lazy loaded coz not `virtual`
    }
    
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-12-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多