C# EF Core 8.0 的行为不符合预期

问题描述 投票:0回答:1

我正在使用 EF Core 来处理数据(而且我是 EF 的新手)。我有一个 DbContext,用于从 SQL 服务器获取数据。将数据加载到内存中后,我更改不同行上的值,但尚未将数据写回 SQL(我想仅在用户单击“确定”按钮时写入数据库)。

这正是发生的事情:我有一个名为

Equipments
的表,其中有一列名为
FkIdType
。我将行
FkIdType
值从 null 更改为 5,例如:

var equ = DataAccess.GetEquipment(pkIdEqu);
equ.FkIdEquipmentType = (int)GVEquipmentTypes.GetFocusedRowCellValue(colPkId);

DataAccess
是一个辅助类,只做一个

context.Where(x => x.PkId == pkID).FirstOrDefault();

之后,我想获取所有

Equipments
的列表,其中
FkIdType
为5。查询如下:

var query = context.Equipments.Where(x => x.FkIdType == 5);
query.ToList();

问题来了。如果我放置一个断点并检查

context.Equipments
,我可以清楚地看到该值已更改。但是,查询不会返回任何内容(如果它是
FkIdType
且值为 5 的唯一行)。为什么?

我尝试直接在数据库中更改值(使用 SSMS 手动),看起来查询实际上是在数据库中查找,而不是在本地上下文中查找。我不明白为什么。

这是我尝试过的:

  1. 强行
    ChangeTracker.LazyLoadingEnabled = false;
  2. 尝试使用
    context.Database.BeginTransaction();
  3. 访问“另一方”的数据。我的意思是使用这样的类型表:
Types.Where(x => x.PkId == FkIdType).Select(x => x.Equipments).ToList();

但是同样奇怪的事情发生了。如果我执行代码,列表为空。如果我“检查”类型对象并在中断模式下打开“结果视图”属性,那么我会看到数据,然后查询返回包含预期数据的列表...为什么?

c# entity-framework-core c#-8.0
1个回答
0
投票

虽然这种行为可能让人感觉不对,但它的行为方式是可以解释的。问题是,当您修改跟踪实体时,EF 将返回该跟踪实体来代替读取的数据,但只有当该记录由读取的数据标识时,它才会这样做。

跑步时:

var query = context.Equipments.Where(x => x.FkIdType == 5);
query.ToList();

这会生成类似于以下内容的 SQL 查询:

SELECT * FROM [dbo].Equipments WHERE FkIdType == 5

问题就出在这里。 EF 将访问数据库尝试查找任何匹配的行。无论它是否找到任何内容,它都不会找到您有待更改的行。 EF 将用它正在跟踪的实体替换它读取的任何实体,但它不会将跟踪缓存作为查询的一部分进行扫描。如果您通过某些其他通用标识符查询行,其中修改的行是从 SQL 查询返回的,则 FkIdType 为 5 的跟踪的修改实体将在结果中被交换。 解决此问题的一个方法是,如果您可能修改了要包含的状态,则将数据加载到跟踪缓存中,然后显式查询跟踪缓存:

context.Equipments.Where(x => x.FkIdType == 5).ToList(); var equipments = context.Equipments.Local .Where(x => x.FkIdType == 5).ToList();

这里执行第一个查询,默认情况下会将所选项目加载到跟踪缓存中。第二条语句针对本地跟踪缓存执行,其中包括新加载的实体以及任何可能修改的实体。最终,最好在读取数据之前用 
SaveChanges()

确定更新状态。将修改的行留在更改跟踪中任何时间都可能最终导致 DbContext 中毒,其中跟踪的更改变得无效并坐在那里,从而阻止未来的

SaveChanges()
调用。
    

© www.soinside.com 2019 - 2024. All rights reserved.