重复Include同一表是否属于代码坏味道?有无更优查询方案?
重复Include同一导航属性的代码问题与优化方案
一、重复Include是否属于代码坏味道?
是的,这种写法属于代码冗余的坏味道。虽然EF Core内部会自动合并重复的Include请求,不会生成重复的SQL JOIN,不会影响查询性能,但重复写Include(n => n.Items)和ThenInclude(n => n.ShoesList)完全没必要,会让代码显得臃肿,降低可读性和维护性——后续修改关联属性时,可能需要修改多处重复代码,增加出错概率。
二、更优的实现方法
你可以将同一上层导航属性的多个关联查询合并到一个Include链中,无需重复Include上层节点。针对你的场景,有两种简洁的写法:
方法1:强类型链式合并(推荐)
利用EF Core的ThenInclude支持在同一层级添加多个关联属性的特性,通过一次Include(n => n.Items)后,多次对ShoesList添加不同的ThenInclude:
public async Task<ShoppingCart> GetCartWithItems(string phoneNum) { return await _context.ShoppingCarts.Where(n => n.UserPhoneNum == phoneNum) .Include(n => n.Items) .ThenInclude(n => n.ShoesList) .ThenInclude(n => n.ShoesColors) .ThenInclude(n => n.ShoesSizes) .ThenInclude(n => n.ShoesList) // 复用上层的Items->ShoesList,添加第二个关联属性 .ThenInclude(n => n.ShoesImages) .FirstAsync(); }
方法2:使用Include的重载(一次性指定多个导航路径)
如果你习惯更紧凑的写法,也可以使用Include的字符串重载(注意:字符串写法不支持编译时检查,属性名变更时容易出错,谨慎使用):
public async Task<ShoppingCart> GetCartWithItems(string phoneNum) { return await _context.ShoppingCarts.Where(n => n.UserPhoneNum == phoneNum) .Include("Items.ShoesList.ShoesColors.ShoesSizes") .Include("Items.ShoesList.ShoesImages") .FirstAsync(); }
三、优化后的效果
两种优化写法最终生成的SQL和你原来的代码完全一致,但代码更简洁、结构更清晰,后续维护时只需要修改一处上层导航的关联逻辑即可,避免了冗余代码带来的潜在问题。
内容的提问来源于stack exchange,提问作者Senpie.mmd
相关产品推荐
相关产品推荐

