简体   繁体   English

使用 AsNoTracking() 延迟加载实体框架

[英]Entity Framework lazy loading with AsNoTracking()

We are currently using lazy loading for Entity Framework and running into out of memory exception .我们目前正在为实体框架使用延迟加载并遇到out of memory exception The reason why we're running into this exception is because the Linq query loads a lot of data and at latter stages it's using lazy loading to load navigation properties.我们遇到这个异常的原因是因为 Linq 查询加载了大量数据,并且在后期阶段它使用延迟加载来加载导航属性。 But because we don't use NoTrackingChanges Entity Framework cache builds up really quickly which results in out of memory error.但是因为我们不使用NoTrackingChanges实体框架缓存构建得非常快,这会导致内存不足错误。

My understanding with EF is the we should always use NoTrackingChanges on query unless you want to update the returned object from the query.我对 EF 的理解是,除非您想更新查询中返回的对象,否则我们应该始终在查询中使用NoTrackingChanges

I then tested using NoChangeTracking :然后我使用NoChangeTracking进行了测试:

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

but I get the following error:但我收到以下错误:

System.InvalidOperationException: When an object is returned with a NoTracking merge option, Load can only be called when the EntityCollection or EntityReference does not contain objects. System.InvalidOperationException:当返回带有 NoTracking 合并选项的对象时,仅当 EntityCollection 或 EntityReference 不包含对象时才能调用 Load。

You've specified for EF to not track your instantiated Account value:您已指定 EF 不跟踪您的实例化Account值:

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

Thus trying to access navigation properties off of them will never work:因此,尝试访问导航属性将永远不会奏效:

var contactName = account.Contact.Name

You can explicitly include navigation properties you want by using the Include() .您可以使用Include()显式包含所需的导航属性。 So the following should work:所以以下应该工作:

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

I'm really not convinced that using AsNoTracking prevents from using lazy loading我真的不相信使用 AsNoTracking 可以防止使用延迟加载

It can be tested really quickly:它可以非常快速地进行测试:

DotNetFiddle Full Example DotNetFiddle 完整示例

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);
    }
}

Output:输出:

========= Start Add: movie1 ============== ======== 开始添加:movie1 ==============
========= END Add: movie1 ============== ========== 结束添加:movie1 ============
Vin Diesel范·迪塞尔
Vin Diesel范·迪塞尔
Run-time exception (line 31): Object reference not set to an instance of an object.运行时异常(第 31 行):未将对象引用设置为对象的实例。

The variable m1 is tracked by the context, thus it can Lazy Load the navigation property and prints the value.变量m1由上下文跟踪,因此它可以延迟加载导航属性并打印值。 m2 is not tracked, but I've explicitly included the navigation property so it prints the value. m2没有被跟踪,但我已经明确地包含了导航属性,所以它会打印值。 m3 is not tracked and I have not included it explicitly thus the value is null and we get a NRE. m3没有被跟踪,我没有明确包含它,因此该值为null ,我们得到了一个 NRE。

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

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