[英]SingleOrDefault and FirstOrDefault returning cached data
我之前编写的一些代码使用Find()
方法通过主键检索单个实体:
return myContext.Products.Find(id)
这很有效,因为我将这段代码放入一个通用类中,并且每个实体都有一个不同的字段名称作为其主键。
但是我不得不替换代码,因为我注意到它正在返回缓存数据,并且每次调用时我都需要它从数据库中返回数据。 微软的文档证实这是Find()
的行为。
所以我将代码更改为使用SingleOrDefault
或FirstOrDefault
。 我没有在文档中找到任何说明这些方法返回缓存数据的内容。
现在我正在执行这些步骤:
SingleOrDefault
或FirstOrDefault
将实体检索到新的实体变量中。 返回的实体在“ Description
字段中仍具有旧值。
我已经运行了 SQL 跟踪,并验证了在第 3 步期间正在查询数据。这让我感到困惑 - 如果 EF 往返于数据库,为什么它返回缓存数据?
我在网上搜索过,大多数答案都适用于Find()
方法。 此外,他们提出了一些解决方案,这些解决方案仅仅是解决方法(处理DbContext
并实例化一个新的)或对我不起作用的解决方案(使用AsNoTracking()
方法)。
如何从数据库中检索我的实体并绕过 EF 缓存?
您所看到的行为在 Microsoft 的How Queries Work文章中的第 3 点下进行了描述:
- 对于结果集中的每个项目
一种。 如果这是一个跟踪查询,EF 检查数据是否表示上下文实例的更改跟踪器中已有的实体
- 如果是,则返回现有实体
在 这篇博文中对它的描述要好一些:
事实证明,实体框架使用身份映射模式。 这意味着一旦具有给定键的实体被加载到上下文的缓存中,只要该上下文存在,它就永远不会再次加载。 因此,当我们第二次访问数据库以获取客户时,它从数据库中检索了更新的
851
记录,但由于客户851
已经加载到上下文中,因此它忽略了数据库中更新的记录( 更多详细信息)。
所有这一切都是说,如果您进行查询,它会首先检查主键以查看它是否已经在缓存中。 如果是这样,它将使用缓存中的内容。
你如何避免它? 第一个是确保您的DbContext
对象不会存活太久。 DbContext
对象仅设计用于一个工作单元。 如果您将其保留太久,则会发生不好的事情,例如过多的内存消耗。
DbContext
以获取数据并丢弃该DbContext
。DbContext
,更新记录并丢弃该DbContext
。 这就是为什么当您在 ASP.NET Core 中使用具有依赖项注入的EF Core 时,它创建时具有作用域生命周期,因此任何DbContext
对象仅在一个 HTTP 请求的生命周期内有效。
在极少数情况下,您确实需要为已有对象的记录获取新数据,您可以像这样使用EntityEntry.Reload() / EntityEntry.ReloadAsync :
myContext.Entry(myProduct).Reload();
但是,如果您只知道 ID,那对您没有帮助。
如果你真的需要重新加载的实体,您只对,你可以做这样一些奇怪的ID:
private Product GetProductById(int id) {
//check if it's in the cache already
var cachedEntity = myContext.ChangeTracker.Entries<Product>()
.FirstOrDefault(p => p.Entity.Id == id);
if (cachedEntity == null) {
//not in cache - get it from the database
return myContext.Products.Find(id);
} else {
//we already have it - reload it
cachedEntity.Reload();
return cachedEntity.Entity;
}
}
但同样,这应该只在有限的情况下使用,当您已经解决了任何长期存在的DbContext
对象的情况时,因为不需要的缓存不是唯一的后果。
好吧,我也遇到了同样的问题,终于找到了答案,
你做的一切都是正确的,这就是 EF 的工作方式。 您可以将.AsNoTracking()
用于您的目的:
return myContext.Products.AsNoTracking().Find(id)
确保您using Microsoft.EntityFrameworkCore;
添加using Microsoft.EntityFrameworkCore;
在顶部。
它像魔术一样工作
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.