.net 为什么EF Core在查询时返回未添加到上下文的实体,但在从上下文中删除时不会删除它们

egdjgwm8  于 2023-11-20  发布在  .NET
关注(0)|答案(2)|浏览(155)

我正在向上下文添加字段。当我编写包含字段的查询时。它将包含已添加到上下文但未保存的字段。我没有找到任何解释此行为的文档,所以任何人们知道的都将受到赞赏。我的下一个问题是为什么/如果我从上下文中删除了一些东西,但没有将更改提交到数据库,那么我该如何做到这一点呢?
这背后的原因是,如果计算失败,我需要添加回删除的实体,那么可以轻松回滚。
示例代码:
f3包含新添加的字段
x1c 0d1x的数据
f3仍然包含保存的字段,即使它已从上下文中删除,与添加行为相比,这似乎是意外的。这应该是预期的吗?

cgvd09ve

cgvd09ve1#

这可能值得在Github上向EF Core团队提出(https://github.com/dotnet/efcore/issues
我去写了一个测试来调查EF Core中的这种行为并确认它,然后在EF 6中尝试它,它确实表现得不同,而且更麻烦的是,当农场重新加载时,从农场中删除字段。
两者的行为是一致的,但在仅按场ID加载字段时不同。例如:

context.Add(field);
var f2 = context.Fields.Where(x=> x.FarmId == 12).ToList();
context.Remove(field);
var f3 = context.Fields.Where(x=> x.FarmId == 12).ToList();

字符串
在这种情况下,两个查询都不返回新添加的字段。
此问题可能与EF Core的跟踪缓存行为存在差异有关。Fields的跟踪缓存正在正确更新,但Farm跟踪缓存跟踪的项目挂起到已标记为已删除的引用上。例如:

int count = context.Fields.Local.Count; // 0
context.Add(field);
count = context.Fields.Local.Count; // 1
var f2 = context.Farm.Include(x=>x.Fields).Single(x=> x.FarmId == 12);
count = context.Fields.Local.Count; // 3 (If farm had 2 existing fields)
context.Remove(field);
count = context.Fields.Local.Count; // 2 (Field is removed from tracking cache as expected.)
var f3 = context.Farm.Include(x=>x.Fields).Single(x=> x.FarmId == 12);


字段从跟踪缓存中删除,但在EF Core再次从场的跟踪缓存中检索场时,它仍然与删除的字段相关联。
纠正该行为的一个解决方案是在重新加载之前分离任何现有的跟踪场:

context.Add(field);
var f2 = context.Farm.Include(x=>x.Fields).Single(x=> x.FarmId == 12);
context.Remove(field);
context.Entry(f2).State = EntityState.Detached;
var f3 = context.Farm.Include(x=>x.Fields).Single(x=> x.FarmId == 12);


现在移除的字段在获取农场时不会被重新加载。正如前面提到的,这似乎是EF Core中的一个bug。
当涉及到计算时,我通常会在内存中执行这些操作,而不是使用或依赖于通过操作/评估添加和删除实体,而是将初始状态加载到内存中,应用更改,然后基于最终所需的状态,在最后添加/删除/更新实体。

smtd7mpg

smtd7mpg2#

EF7的“修复”是在将删除持久化到数据库之前开始跟踪以前相关的实体时修复已删除的实体,该修复被列为EF7的重大更改。如果升级到EF7,则不应再观察该行为。
Issue on GitHub

相关问题