在Asp.net中为每个查询创建DbContext是否只使EF从其缓存中读取数据,或者每次都查询整个集合的数据?我知道每个AppDomain的元数据缓存,但只是数据呢?
上下文:使用MVC4 + Web API前端的数据采集和可视化应用程序不会称之为“高容量”,但是许多查询会在更短的时间内返回相同的数据集。
答案 0 :(得分:14)
实体框架每个AppDomain没有数据缓存,每个上下文实例只有一个缓存。
如果您为每个请求或查询创建新上下文,则从空缓存开始,EF将从数据库中获取数据。
此外,术语“每个上下文实例的缓存”可能会产生误导,因为它并不意味着如果实体已经加载到上下文缓存中,EF将不会对数据库运行查询。此缓存的工作方式以及如何利用它(或不使用)如下:
DbSet<T>
或IQueryable<T>
上的每个 LINQ到实体查询都会运行数据库查询,无论实体是否已存在背景与否。但是,如果在上下文中已存在与查询实体具有相同密钥的实体,EF将抛出该查询的结果并将缓存的实体实例返回给调用者。
检查具有相同密钥的实体是否运行查询后执行此检查。 (对于复杂查询 - 例如包含Include
的查询 - 它之前无法执行此检查,因为它无法知道将返回哪些实体和键值。)
这是默认行为(MergeOption
是AppendOnly
)。我相信您可以将此行为更改为OverwriteChanges
和其他选项,但它们都不会避免LINQ查询始终发出数据库查询。
要仅通过密钥查询实体,您可以使用GetObjectByKey
或Find
(带DbContext
),这将首先检查具有该密钥的实体是否已缓存在上下文然后返回此缓存对象。如果不是,它将运行数据库查询以加载它。
您可以查询EF的ChangeTracker,尤其是DbContext
支持,您可以通过DbSet<T>.Local
集合访问上下文缓存。
这里的问题是,如果Local
上的查询未返回结果,则无法自动查询数据库。你必须手动编写这个逻辑。更大的问题是Local
上的查询是LINQ到对象而不是LINQ到实体(Local
没有实现IQueryable<T>
,只有IEnumerable<T>
) ,所以你经常需要重写你的查询以对Local
采取行动 - 例如你不能在这里使用Include
,你不能使用任何EntityFunctions
,你会得到不同的行为关于区分大小写等的字符串比较