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



我们目前正在为实体框架使用延迟加载,并运行到out of memory exception中。我们遇到这种异常的原因是,Linq查询加载了大量数据,而在后面的阶段,它使用延迟加载来加载导航属性。但是,由于我们不使用NoTrackingChanges实体框架,缓存构建非常快,这会导致内存不足错误。

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

然后我使用NoChangeTracking:进行了测试

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

但我得到以下错误:

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

您已指定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完整示例

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================
=============
Vin Diesel
运行时异常(第31行):对象引用未设置为对象的实例。

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

最新更新