如何将带JOIN的原生SQL查询改写为EF Core LINQ语句
问题分析
- 投影时Id字段赋值错误:Join之后的投影代码中,你把新User对象的
Id属性赋值为lifeCycle.Id(生命周期表的主键),而非关联的用户表u.Id。后续Where(u => u.Id == 123)过滤的是生命周期表的Id,和原SQL过滤用户表Id=123的逻辑完全不符。当EF Core检测到该过滤条件无匹配可能时,就会直接生成WHERE FALSE的无效语句。 - 排序规则错误:原SQL是
ORDER BY created DESC降序排序,你写的OrderBy(c => c.Created)是升序排序,排序方向不符。 - 过滤时机不符合原SQL逻辑:原SQL是先对
users表过滤出Id=123的记录再做关联,现有代码是关联全量用户表之后再做过滤,执行效率更低。
修正后的LINQ代码
优先贴合原SQL逻辑的写法如下:
var users = db.LifeCycle // 先过滤生命周期表updated为null的记录 .Where(l => l.Updated == null) // 先过滤用户表Id=123,对应原SQL的子查询逻辑 .Join(db.Users.Where(u => u.Id == 123), l => l.Reference, u => u.Id, (lifeCycle, user) => new User() { // 修正Id赋值,避免和用户表Id冲突 Id = user.Id, FieldOne = user.FieldOne, FieldTwo = user.FieldTwo, Created = lifeCycle.Created }) // 改为降序排序,和原SQL逻辑对齐 .OrderByDescending(c => c.Created) .ToList();
如果你已经在EF Core中配置了LifeCycle和User的外键导航属性,还可以用更简洁的写法:
var users = db.LifeCycle .Where(l => l.Updated == null && l.Reference == 123) .Include(l => l.User) .OrderByDescending(l => l.Created) .Select(l => new User() { Id = l.User.Id, FieldOne = l.User.FieldOne, FieldTwo = l.User.FieldTwo, Created = l.Created }) .ToList();
内容的提问来源于stack exchange,提问作者stoner
相关产品推荐
相关产品推荐

