gpt4 book ai didi

c# - SingleOrDefault 和 FirstOrDefault 返回缓存数据

转载 作者:行者123 更新时间:2023-12-03 23:51:32 25 4
gpt4 key购买 nike

我之前写的一些代码使用了 Find()通过主键检索单个实体的方法:

return myContext.Products.Find(id)

这很有效,因为我将这段代码放入一个通用类中,并且每个实体都有一个不同的字段名称作为其主键。

但是我不得不替换代码,因为我注意到它正在返回缓存数据,并且每次调用时我都需要它从数据库中返回数据。微软的文档证实这是 Find() 的行为。 .

所以我改变了我的代码使用 SingleOrDefaultFirstOrDefault .我没有在文档中找到任何说明这些方法返回缓存数据的内容。

现在我正在执行这些步骤:
  • 通过 EF 保存实体。
  • 在 SSMS 中执行 UPDATE 语句来更新最近保存的
    记录的描述字段。
  • 使用 SingleOrDefault 将实体检索到新的实体变量中
    FirstOrDefault .

  • 返回的实体仍然具有 Description 中的旧值 field 。

    我已经运行了 SQL 跟踪,并验证了在第 3 步期间正在查询数据。这让我感到困惑 - 如果 EF 往返于数据库,为什么它返回缓存数据?

    我在网上搜索过,大多数答案都适用于 Find()方法。此外,他们提出了一些解决方案,这些解决方案仅仅是解决方法(处理 DbContext 并实例化一个新的)或对我不起作用的解决方案(使用 AsNoTracking() 方法)。

    如何从数据库中检索我的实体并绕过 EF 缓存?

    最佳答案

    您所看到的行为在 Microsoft 的 How Queries Work 中有所描述。第3条下的条款:

    1. For each item in the result set

    a. If this is a tracking query, EF checks if the data represents an entity already in the change tracker for the context instance

    • If so, the existing entity is returned


    this blog post 中对它的描述要好一些:

    It turns out that Entity Framework uses the Identity Map pattern. This means that once an entity with a given key is loaded in the context’s cache, it is never loaded again for as long as that context exists. So when we hit the database a second time to get the customers, it retrieved the updated 851 record from the database, but because customer 851 was already loaded in the context, it ignored the newer record from the database (more details).



    所有这一切都是说,如果您进行查询,它会首先检查主键以查看它是否已经在缓存中。如果是这样,它将使用缓存中的内容。

    你如何避免它?首先是确保您没有保留您的 DbContext对象存活时间过长。 DbContext对象仅设计用于一个工作单元。如果您将其保留太久,则会发生不好的事情,例如过多的内存消耗。
  • 您是否需要检索数据以显示给用户?创建一个 DbContext获取数据并丢弃 DbContext .
  • 您需要更新记录吗?新建 DbContext , 更新记录并丢弃 DbContext .

  • 这就是为什么,当您使用 EF Core 时 with dependency injection在 ASP.NET Core 中,它是用 scoped 创建的生命周期,所以任何 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对象,因为不需要的缓存不是唯一的后果。

    关于c# - SingleOrDefault 和 FirstOrDefault 返回缓存数据,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57061496/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com