目前,我们正在对Entity Framework使用延迟加载并运行到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。
您已指定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会阻止使用延迟加载
可以很快地对其进行测试:
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
=======================结束添加:movie1 =========== ====
Vin Diesel
Vin Diesel
运行时异常(第31行):对象引用未设置为对象的实例。
该变量m1
由上下文跟踪,因此可以延迟加载导航属性并打印该值。m2
不会被跟踪,但是我明确包含了navigation属性,因此它会打印值。m3
不会被跟踪,并且我也没有明确地包含它,因此该值为null
,我们得到了NRE。
本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句