【问题标题】:Entity Framework lazy loading with AsNoTracking()使用 AsNoTracking() 进行实体框架延迟加载
【发布时间】:2017-11-08 20:03:13
【问题描述】:

我们目前正在为实体框架使用延迟加载并遇到out of memory exception。我们遇到此异常的原因是因为 Linq 查询加载了大量数据,并且在后期它使用延迟加载来加载导航属性。但是因为我们不使用NoTrackingChanges Entity Framework 缓存构建得非常快,这会导致内存不足错误。

我对 EF 的理解是,我们应该始终在查询中使用 NoTrackingChanges,除非您想从查询中更新返回的对象。

然后我使用NoChangeTracking进行测试:

var account = _dbcontext.Account
                        .AsNoTracking()
                        .SingleOrDefault(m => m.id == 1); 
var contactName = account.Contact.Name

但我收到以下错误:

System.InvalidOperationException:当返回一个带有 NoTracking 合并选项的对象时,只有在 EntityCollection 或 EntityReference 不包含对象时才能调用 Load。

【问题讨论】:

  • 请提供导致此异常的代码。
  • @SteveGreene 如果我禁用代理创建,那么延迟加载将不起作用。这是真的吗?
  • @ErikPhilips var account = _dbcontext.Account.AsNoTracking().SingleOrDefault(m=>m.id == 1); var contactName = account.Contact.Name
  • 不要将代码或直接相关的 cmets 添加为 cmets,只需更新您的问题,这样其他用户就不必费力通过 cmets 来理解问题。

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


【解决方案1】:

您已指定 EF 不跟踪您的实例化 Account 值:

var account = _dbcontext.Account.AsNoTracking().SingleOrDefault(m=>m.id == 1);

因此,试图从它们中访问导航属性永远不会奏效:

var contactName = account.Contact.Name

您可以使用Include() 明确包含所需的导航属性。所以以下应该工作:

var account = _dbcontext.Account
  .Include(a => a.Contact)
  .AsNoTracking()
  .SingleOrDefault(m=>m.id == 1);

var contactName = account.Contact.Name;  // no exception, it's already loaded

我真的不相信使用 AsNoTracking 会阻止使用延迟加载

可以很快测试:

DotNetFiddle Full Example

public static void Main()
{
    var actor1 = new Actor { Id = 1, Name = "Vin Diesel" }; 
    var movie1 = new Movie { Id = 1, Title = "Fast and Furious", PrimaryActor = actor1 };
    using (var context = new MovieDb())
    {

        Console.WriteLine("========= Start Add: movie1 ==============");
        context.Movies.Add(movie1);
        context.SaveChanges();
        Console.WriteLine("========= END Add: movie1 ==============");

        var m1 = context.Movies.First();
        Console.WriteLine(m1.PrimaryActor.Name);

        var m2 = context.Movies.Include(m => m.PrimaryActor).AsNoTracking().First();
        Console.WriteLine(m2.PrimaryActor.Name);

        var m3 = context.Movies.AsNoTracking().First();
        Console.WriteLine(m3.PrimaryActor.Name);
    }
}

输出:

========= 开始添加:movie1 ==============
========= END 添加:movie1 ===============
范·迪塞尔
范·迪塞尔
运行时异常(第 31 行):对象引用未设置为对象的实例。

变量m1被上下文跟踪,因此它可以延迟加载导航属性并打印值。 m2 未被跟踪,但我已明确包含导航属性,因此它会打印该值。 m3 没有被跟踪,我也没有明确包含它,因此值为 null,我们得到一个 NRE。

【讨论】:

  • 当您需要将递归实体加载为无跟踪时,这确实是一个 catch-22....
  • @DouglasGaskell 一点也不。
  • @ErikPhilips 谢谢你的回答。我真的不相信使用 AsNoTracking 可以防止使用延迟加载,但是要找到有关它的信息并不容易。您能否提供有关您所说内容的参考资料?
  • 这里也一样。使用 AsNoTracking 进行延迟加载...您可以掷硬币判断它是否有效。有时会,有时不会。
猜你喜欢
  • 2013-12-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多