EF Core 2.0带Where条件查询时未加载关联子实体问题咨询
Children子实体加载差异的本质 这事儿的核心在于EF Core的**关联固定(Relationship Fixup)**机制,以及你两个查询加载到上下文的实体范围不同,咱们一步步拆解:
1. 不带Where的查询为何自动填充Children
当你执行以下查询时:
return await Context.Set<Category>() .OrderBy(c => c.Description) .ToListAsync();
EF Core会把数据库中所有Category实体完整加载到上下文的跟踪缓存里。
此时EF Core会触发关联固定逻辑:它会遍历所有已加载的Category实体,根据ParentCategoryId与CategoryId的匹配关系,自动将子实体填充到对应父实体的Children集合中,同时把父实体关联到子实体的ParentCategory属性上。你看到的Children被加载,其实并没有额外发起数据库查询,只是EF Core在内存中帮你把已加载的实体关系串联了起来。
2. 带Where的查询为何无法加载Children
当你添加Where(c => c.CategoryId == id)条件后:
return await Context.Set<Category>() .Where(c => c.CategoryId == id) .OrderBy(c => c.Description) .ToListAsync();
EF Core只会加载符合条件的单个/少数Category实体到上下文缓存中。此时,这些父实体对应的子实体并没有被查询加载到缓存里,关联固定没有可匹配的子实体,自然Children集合就保持构造函数初始化后的空列表状态。
而当你加上.Include(c => c.Children)时,EF Core会执行关联查询,将父实体及其对应的子实体一次性加载到缓存中,关联固定就能正常建立父子关系,Children也就被正确填充了。
3. 为什么延迟加载没生效?
你可能会好奇为什么没触发延迟加载——那是因为你的导航属性(ParentCategory和Children)没有标记为virtual。EF Core的延迟加载要求导航属性必须是virtual(同时上下文默认启用延迟加载),否则延迟加载逻辑会失效。如果把这些属性改成virtual,即使不带Include,当你访问Children集合时,EF Core会自动发起数据库查询加载子实体,但这种方式容易引发N+1查询问题,所以显式使用Include是更推荐的做法。
内容的提问来源于stack exchange,提问作者Juanma

