Entity Framework lazy loading with AsNoTracking()(使用 AsNoTracking() 进行实体框架延迟加载)
问题描述
我们目前正在为实体框架使用延迟加载并遇到内存不足异常
.我们遇到这个异常的原因是因为 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;//没有异常,已经加载了
<块引用>
我真的不相信使用 AsNoTracking 会阻止使用延迟加载
可以很快测试:
DotNetFiddle 完整示例
public static void Main(){var actor1 = 新演员 { Id = 1, Name = "Vin Diesel" };var movie1 = new Movie { Id = 1, Title = "速度与激情", PrimaryActor = actor1 };使用 (var context = new MovieDb()){Console.WriteLine("========= 开始添加:movie1 ==============");context.Movies.Add(movie1);context.SaveChanges();Console.WriteLine("========= END 添加: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.
We are currently using lazy loading for Entity Framework and running into 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. But because we don't use NoTrackingChanges
Entity Framework cache builds up really quickly which results in out of memory error.
My understanding with EF is the we should always use NoTrackingChanges
on query unless you want to update the returned object from the query.
I then tested using 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.
You've specified for EF to not track your instantiated Account
value:
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()
. 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
It can be tested really quickly:
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);
}
}
Output:
========= Start Add: movie1 ==============
========= END Add: movie1 ==============
Vin Diesel
Vin Diesel
Run-time exception (line 31): Object reference not set to an instance of an object.
The variable m1
is tracked by the context, thus it can Lazy Load the navigation property and prints the value. m2
is not tracked, but I've explicitly included the navigation property so it prints the value. m3
is not tracked and I have not included it explicitly thus the value is null
and we get a NRE.
这篇关于使用 AsNoTracking() 进行实体框架延迟加载的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持编程学习网!
本文标题为:使用 AsNoTracking() 进行实体框架延迟加载
- MoreLinq maxBy vs LINQ max + where 2022-01-01
- 在哪里可以找到使用中的C#/XML文档注释的好例子? 2022-01-01
- 如何用自己压缩一个 IEnumerable 2022-01-01
- 带有服务/守护程序应用程序的 Microsoft Graph CSharp SDK 和 OneDrive for Business - 配额方面返回 null 2022-01-01
- 良好实践:如何重用 .csproj 和 .sln 文件来为 CI 创建 2022-01-01
- WebMatrix WebSecurity PasswordSalt 2022-01-01
- 输入按键事件处理程序 2022-01-01
- C#MongoDB使用Builders查找派生对象 2022-09-04
- Web Api 中的 Swagger .netcore 3.1,使用 swagger UI 设置日期时间格式 2022-01-01
- C# 中多线程网络服务器的模式 2022-01-01