ASP.NET EF Core中DbSet.Find为何无法找到已添加未保存的跟踪对象?
问题解答
核心原因
你猜的完全正确:每个HTTP请求都会创建全新的ApplicationContext实例,这就是实体跟踪无法跨请求生效的根本原因。
详细解释
ASP.NET Core中,通过AddDbContext注册的DbContext默认是作用域(Scoped)服务——这意味着每个请求都会生成一个独立的DbContext实例,各个实例的实体跟踪缓存是完全隔离的:
- 在
Add接口的请求中,你调用context.Records.AddAsync(item)只是把实体加入了当前请求DbContext的跟踪集合,这个实体仅存在于该DbContext的内存缓存里,既没有写入数据库,也不会同步到其他DbContext实例。 - 后续调用
Query接口时,系统会创建一个全新的DbContext,它的跟踪缓存是空的,FindAsync会优先检查自身的跟踪缓存,找不到就去数据库查询。而数据库里因为之前没调用SaveChangesAsync,根本没有这条数据,所以返回null。
纠正误解
DbContext的实体跟踪是实例级别的局部缓存,并非全局共享的存储。AddAsync的作用是让当前DbContext开始跟踪这个实体,方便后续在同一个DbContext生命周期内(比如同一个请求里)直接读取或修改,但它不会自动将实体持久化到数据库,也无法让其他DbContext感知到这个实体的存在。
只有调用SaveChangesAsync,才会把跟踪的实体变更写入数据库,这样所有后续请求的DbContext都能通过数据库查询到这条数据。
补充说明
- 如果是同一个请求内,在
AddAsync之后不调用SaveChangesAsync,直接调用FindAsync是可以获取到实体的,因为用的是同一个DbContext实例。 - 你提到的用Record类型作为实体,确实和这个问题无关,EF Core完全支持Record作为实体类型,只要主键等配置正确即可。
内容的提问来源于stack exchange,提问作者Leonel Hou
相关产品推荐
相关产品推荐

