在 Asp.net 中为每个查询创建 DbContext 是否会使 EF 仅从其缓存中读取数据,还是每次都查询整个集合的 DB?我知道每个 AppDomain 的元数据缓存,但是数据呢?
上下文:具有 MVC4 + Web API 前端的数据采集和可视化应用程序,不会称其为“大容量”,但许多查询会在更短的时间内返回相同的数据集。
在 Asp.net 中为每个查询创建 DbContext 是否会使 EF 仅从其缓存中读取数据,还是每次都查询整个集合的 DB?我知道每个 AppDomain 的元数据缓存,但是数据呢?
上下文:具有 MVC4 + Web API 前端的数据采集和可视化应用程序,不会称其为“大容量”,但许多查询会在更短的时间内返回相同的数据集。
Entity Framework 没有每个 AppDomain 的数据缓存,只有每个上下文实例的缓存。
如果您为每个请求或查询创建一个新上下文,您将从一个空缓存开始,EF 将从数据库中获取数据。
此外,术语“每个上下文实例缓存”可能会产生误导,因为这并不意味着如果实体已加载到上下文缓存中,EF 将不会对数据库运行查询。此缓存的工作方式以及如何利用(或不利用)它如下:
DbSet<T>
在 a 上或通常在 an上的每个LINQ-to-Entities 查询IQueryable<T>
都将运行数据库查询,无论实体是否已存在于上下文中。但是,如果上下文中已经存在与查询实体具有相同键的实体,EF 将丢弃该查询的结果并将缓存的实体实例返回给调用者。
它会在运行查询后检查是否存在具有相同键的实体。(对于复杂的查询——例如包含一个的查询Include
——它之前不能做这个检查,因为它不知道将返回哪些实体和键值。)
这是默认行为(MergeOption
is AppendOnly
)。我相信,您可以将此行为更改为OverwriteChanges
和其他选项,但它们都不会避免 LINQ 查询总是发出数据库查询。
要仅通过键查询实体,您可以使用GetObjectByKey
or 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
,你会在区分大小写等方面得到不同的字符串比较行为。