如何用LINQ关联两张表且对带外键的子表加where条件[EF Core]
错误原因
你当前代码通过Select投影生成了匿名类型的集合,和接口约定返回的IEnumerable<Rha>类型不匹配,因此触发类型转换异常,和你是否使用JOIN写法没有关联。
解决方案
方案1:使用带过滤的Include(EF Core 5.0+ 推荐)
如果你的Rha实体类本身已经定义了SubRhas导航属性,直接用EF Core支持的过滤Include写法即可,返回值天然符合接口类型要求:
public async Task<IEnumerable<Rha>> GetSubRHAByAssign(string assign) { var result = await _db.Rhas // 仅加载Assign匹配的子表数据 .Include(x => x.SubRhas.Where(p => p.Assign == assign)) .AsNoTracking() // 可选:如果只需要返回至少有一条匹配子项的主表数据,加上这行过滤 .Where(x => x.SubRhas.Any(p => p.Assign == assign)) .ToListAsync(); return result; }
方案2:低版本EF Core兼容写法
如果使用的EF Core版本低于5.0,不支持过滤Include,可以先查询符合条件的子表,再聚合主表数据:
public async Task<IEnumerable<Rha>> GetSubRHAByAssign(string assign) { var matchedSubRhas = await _db.SubRhas .Where(p => p.Assign == assign) .Include(p => p.Rha) .AsNoTracking() .ToListAsync(); // 按主表分组聚合子项 return matchedSubRhas .GroupBy(p => p.Rha) .Select(g => { var rha = g.Key; rha.SubRhas = g.ToList(); return rha; }); }
方案3:自定义DTO返回(避免污染原实体导航属性)
如果你不想修改Rha实体自带的SubRhas导航属性内容,可以专门定义返回用的传输对象,调整接口返回类型即可:
- 先定义DTO类
public class RhaWithFilteredSubDto { // 复制Rha类的所有公开字段 public int Id { get; set; } // 其他Rha字段... // 过滤后的子表集合 public IEnumerable<SubRha> MatchedSubRhas { get; set; } }
- 修改接口定义和实现
// 接口修改为返回DTO集合 Task<IEnumerable<RhaWithFilteredSubDto>> GetSubRHAByAssign(string assign); // 实现代码 public async Task<IEnumerable<RhaWithFilteredSubDto>> GetSubRHAByAssign(string assign) { return await _db.Rhas .Select(x => new RhaWithFilteredSubDto { // 赋值Rha所有字段 Id = x.Id, // 其他Rha字段赋值... MatchedSubRhas = x.SubRhas.Where(p => p.Assign == assign) }) .AsNoTracking() .ToListAsync(); }
内容的提问来源于stack exchange,提问作者NeoSoul
相关产品推荐
相关产品推荐

