如何处理实体框架中过时的缓存
本文关键字:框架 过时 缓存 实体 何处理 处理 | 更新日期: 2023-09-27 18:28:17
我从实体框架中得到了非常奇怪的行为。我正在编写一个WebApi应用程序,因此我从浏览器中获得的对象是断开连接/分离的。我返回的数据是事务性的,因此它与数据库中的任何给定表都不匹配。我必须进行大量查找和数据操作,才能对数据库进行实际更新。
我似乎遇到的问题是,在查询数据时,我正在填充Tracked Changes缓存。这对我来说似乎不是问题,因为真正的数据来源应该是数据库。当我最终更改数据并调用SaveChanges时,我会得到约束错误。这是我的台阶。
- 查询数据
- 创建要插入的行
- 将行与数据库进行比较并更改数据库
在查看了Ctx.ChangeTracker.Entries()中的数据后,我发现要删除的条目在本应删除时被标记为Modified。我解决这个问题的方法是为第3步创建一个新的上下文。它神奇地开始工作了。我以为就是这样,但在我的测试用例中,我从数据库中进行最后一次读取,以验证我的事务是否正确写入。我得到了一个额外的行,应该已经删除了。事实上,当直接检查数据库时。再次,一个新的上下文做最后一次阅读解决了这个问题。
我只是假设默认的缓存设置只用于跟踪更改,而不是加速查询。
如果我试图在查询中使用AsNoTracking,我也会遇到麻烦,因为如果我试图删除这样查询的行,我会遇到错误。在我的代码中,我不知道我是要删除还是修改,直到以后。有没有办法清除缓存,这样我就不需要创建新的上下文了?
有没有更好的方法来处理这些问题?
编辑:
在某种程度上,AsNoTracking会起到作用。我仍然发现自己实例化了更多的DbContext副本,以防止出现错误。多对一实体必须按顺序删除,否则会触发空外键错误。
var details = oldInvoice.details.ToList();
Context.Entry(oldInvoice).State = EntityState.Unchanged;
Context.Entry(oldInvoice).State = EntityState.Deleted;
details.ForEach(a => Context.Entry(a).State = EntityState.Deleted);
Entity Framework提供了一个异常DbUpdateConcurrencyException
,您可以在调用SaveChanges()
时捕获它。你可以循环浏览错误,比如这样:
catch (DbUpdateConcurrencyException ex)
{
saveFailed = true;
// Get the current entity values and the values in the database
var entry = ex.Entries.Single();
var currentValues = entry.CurrentValues;
var databaseValues = entry.GetDatabaseValues();
// Choose an initial set of resolved values. In this case we
// make the default be the values currently in the database.
var resolvedValues = databaseValues.Clone();
// Have the user choose what the resolved values should be
HaveUserResolveConcurrency(currentValues, databaseValues,
resolvedValues);
// Update the original values with the database values and
// the current values with whatever the user choose.
entry.OriginalValues.SetValues(databaseValues);
entry.CurrentValues.SetValues(resolvedValues);
}
} while (saveFailed);
此外,您的更新代码听起来也很可疑。通常,当您通过WebApi或其他机制将数据传递给客户端时,返回的数据没有跟踪数据,因此在调用SaveChanges()
之前,您应该检查它是否存在,并将其重新附加到上下文中,如果存在,则将其状态更改为EntityState.Modified
。