如何确认EF Core在同一次请求不同阶段是否重复查询相同Id的对象
你调用Find()方法的时候本身就会优先读取DbContext的本地追踪缓存,默认不会重复查询数据库,这是EF内置的设计规则。
Find()的默认查询优先级
Find()方法接收主键作为参数时,查询顺序固定如下:
- 优先从当前DbContext实例的本地追踪缓存中匹配符合主键的实体,匹配到直接返回,全程不操作数据库
- 本地缓存未匹配到的情况下,才会生成SQL查询请求发往数据库
- 数据库也无匹配记录时返回null
所以只要你两次调用Find()用的是同一个DbContext实例(ASP.NET Core默认注入的DbContext是Scoped生命周期,同一个HTTP请求内会复用同一个实例,符合你的场景),第二次调用相同主键的Find()时,自然会返回本地缓存的实体,不会查库。
主动确认本地是否存在对应实体的方法
如果你需要在调用Find()前就明确知道实体是否已经被缓存,可以直接操作DbSet的Local属性,这个属性是内存中的追踪实体集合,所有操作都不会触发数据库交互:
// 仅查本地缓存,无数据库请求 var cachedUser = dbContext.Users.Local.FirstOrDefault(u => u.Id == 1); if (cachedUser != null) { // 直接使用本地缓存的实体 } else { // 本地没有,再查询数据库 cachedUser = dbContext.Users.Find(1); }
开发阶段验证查询行为的方法
如果要确认有没有触发多余的数据库查询,可以开启EF Core的日志输出,重复调用相同主键的Find()时,只有第一次会出现查询User表的SQL日志,后续调用不会产生新的SQL记录。
注意边界
只有Find()方法有优先查本地缓存的逻辑,如果你用的是FirstOrDefault()、Where()这类普通LINQ查询,默认会直接查询数据库,哪怕本地已经有对应实体。如果要让普通查询也优先走本地,需要先查Local集合再查数据库。
内容的提问来源于stack exchange,提问作者Nico
相关产品推荐
相关产品推荐

