我正在使用 Entity Framework 5.0 和 SQLite 数据库。我有一个场景,我对数据库记录进行修改,然后使用同一表的实体对象的新实例来读取同一记录,但我得到旧值。在调试时,如果我转到数据库工具并查看记录,就会发现更改在那里,但 EF 没有拾取它们。稍后它最终会捡起它们,但我无法确定那是什么时候。
这是代码片段。首先,我使用 SaveChanges() 执行更新:
tblTest efTestTbl = context.tblTests.Find(recID);
context.tblTests.Attach(efTestTbl);
efTestTbl.Value1 = "newValue"; // This changed it from "oldValue" :-)
int changedRecs = context.SaveChanges();
上面的代码似乎总是有效并将更改保存到数据库中。 changedRecs 最终等于 1。我可以在代码中的这一点之后停下来,使用我的数据库工具查看数据库中的值,并且该列将等于“newValue”。
现在,如果我在上次更新后使用不同的表对象但上下文对象的相同实例直接执行以下读取:
tblTest efTestTbl = context.tblTests.Find(recID);
efTestTbl.Value1 中的值将等于“oldValue”。我看到一些关于 EF 不缓存任何内容的评论,但我不敢相信这是真的。在另一个论坛中,我看到一个关于 ObjectQuery 的 MergeOption 的对话,缓存被称为“身份解析”。这是信息丰富的,但对我没有帮助,因为我没有使用查询和“ExecuteNonQuery()”方法。
我的场景需要我写出更改,然后从数据库读取并记录更改作为验证步骤。
如果您能帮助我找到刷新缓存的方法,我将不胜感激。
根据您的上下文中发生的情况,您尝试加载的对象可能已经存在于其他上下文中。
这就是我之前解决此问题的方法;
public static class ZarettoContextExtensionClass
{
public static tblTest Reload(this tblTest item, DbContext c)
{
c.Configuration.AutoDetectChangesEnabled = false;
c.Entry(item).Reload();
c.Configuration.AutoDetectChangesEnabled = true;
return item;
}
}
那么显然你会这样做:
efTestTbl.Reload(context)
我在我正在查询的表上使用了 AsNoTracking() 函数来解决这个问题。在您的情况下,查询将如下所示。
tblTest efTestTbl = context.tblTests.AsNoTracking().FirstOrDefault(t => t.Id == recID);
如果您使用
tblTest efTestTbl = context.tblTests.FirstOrDefault(t => t.Id == recID);
而不是
tblTest efTestTbl = context.tblTests.Find(recID);
您可以确定 EF 将查询数据库并获得持久数据。
使用 Find() 方法 EF 将首先检查对象是否不在您的数据库上下文中,然后才决定是否查询数据库。
这并不能回答为什么你会得到旧数据的问题,但应该可以解决你的问题。
我只是想知道为什么你在已经附加的实体 efTestTbl 上使用 .Attach() 方法? 在我看来,您在某个时刻 Detached() 它,执行了未跟踪的更改,并附加了错误的值(与数据库中不同),这些值后来被幸运的巧合保存了。
您还在使用 AutoDetectChanges 吗?
DbContext 被设计为具有较短的生命周期,其中新实例是 为每个工作单元创建。这种方式意味着所有被跟踪的实体 当上下文被放置在每个末尾时被丢弃 工作单元。但是,使用此方法清除所有跟踪的实体 在创建新上下文实例的情况下可能很有用 不实用。
此方法应始终优于分离每个跟踪的方法 实体。分离实体是一个缓慢的过程,可能会有副作用 影响。此方法在清除所有跟踪的方面更加有效 来自上下文的实体。
请注意,此方法不会生成 StateChanged 事件,因为 实体不是单独分离的。
public class ModelService
{
private readonly IServiceScopeFactory _serviceScopeFactory;
public ModelService(IServiceScopeFactory serviceScopeFactory)
{
_serviceScopeFactory = serviceScopeFactory;
}
public IEnumerable<Chat> GetSentItemsIds(int userId)
{
using (var scope = _serviceScopeFactory.CreateScope())
{
var _DBContext = scope.ServiceProvider.GetService<IContext>();
return _DBContext.Chat.ToList();
}
}
}
请参阅 EF Core 更改跟踪以获取更多信息和示例。 https://learn.microsoft.com/en-us/dotnet/api/microsoft.entityframeworkcore.changetracking.changetracker.clear?view=efcore-8.0