7

在 Asp.net 中为每个查询创建 DbContext 是否会使 EF 仅从其缓存中读取数据,还是每次都查询整个集合的 DB?我知道每个 AppDomain 的元数据缓存,但是数据呢?

上下文:具有 MVC4 + Web API 前端的数据采集和可视化应用程序,不会称其为“大容量”,但许多查询会在更短的时间内返回相同的数据集。

4

1 回答 1

18

Entity Framework 没有每个 AppDomain 的数据缓存,只有每个上下文实例的缓存。

如果您为每个请求或查询创建一个新上下文,您将从一个空缓存开始,EF 将从数据库中获取数据。

此外,术语“每个上下文实例缓存”可能会产生误导,因为这并不意味着如果实体已加载到上下文缓存中,EF 将不会对数据库运行查询。此缓存的工作方式以及如何利用(或不利用)它如下:

  • DbSet<T>在 a 上或通常在 an上的每个LINQ-to-Entities 查询IQueryable<T>都将运行数据库查询,无论实体是否已存在于上下文中。但是,如果上下文中已经存在与查询实体具有相同键的实体,EF 将丢弃该查询的结果并将缓存的实体实例返回给调用者。

    它会在运行查询后检查是否存在具有相同键的实体。(对于复杂的查询——例如包含一个的查询Include——它之前不能做这个检查,因为它不知道将返回哪些实体和键值。)

    这是默认行为(MergeOptionis AppendOnly)。我相信,您可以将此行为更改为OverwriteChanges和其他选项,但它们都不会避免 LINQ 查询总是发出数据库查询。

  • 要仅通过键查询实体,您可以使用GetObjectByKeyor Find(with DbContext) 它将首先检查具有该键的实体是否已缓存在上下文中,然后返回此缓存对象。如果不是,它将运行数据库查询来加载它。

  • 您可以查询 EF 的 ChangeTracker,它特别受支持,您可以通过集合DbContext访问上下文缓存。DbSet<T>.Local

    这里的问题是,如果查询Local不返回结果,则没有自动查询数据库的逻辑。您必须手动编写此逻辑。更大的问题是查询Local是 LINQ-to-Objects 而不是 LINQ-to-Entities (Local不实现IQueryable<T>,仅IEnumerable<T>),因此您经常必须重写查询以执行操作Local- 例如您不能使用Include在这里,你不能使用 any EntityFunctions,你会在区分大小写等方面得到不同的字符串比较行为。

于 2013-06-11T19:05:45.907 回答