如何用Entity Framework Core改写.NET Core 3.1 WebAPI的SQL查询?
解决EF Core LINQ连接查询的作用域错误问题
嘿,我看出来你这儿卡壳的地方了——之前用原生SQL因为邮箱带特殊字符触发MySQL报错,转用EF的LINQ查询又碰到了连接的作用域问题,确实挺让人头疼的。
先看你写的这段出问题的代码:
var query = ( from u in _dbContext.User join userRoles in _dbContext.UsersRoles on u.id equals userRoles.UserId join r in _dbContext.Role on r.id equals userRoles.RoleId where u.email == username select u);
错误提示“名称'r'在'equals'左侧的作用域中不存在”,原因其实很直白:在LINQ的join语法规则里,equals左边必须是前面已经被引入到查询中的集合成员,你这里把r.id放在左边,但r是你当前这个join才要引入的集合,编译器这会儿还不知道r是什么,自然就报错了。
正确的写法应该把userRoles.RoleId放在equals左边,r.Id放在右边——毕竟userRoles是上一个join已经定义好的,编译器能识别它:
// 修正后的查询 var query = from u in _dbContext.User join userRoles in _dbContext.UsersRoles on u.id equals userRoles.UserId join r in _dbContext.Role on userRoles.RoleId equals r.Id // 调换equals左右的顺序 where u.email == username select new { id = u.Id, email = u.Email, name = u.name, lastname = u.lastname, phoneNumber = u.PhoneNumber, role = r.name }; // 获取结果,和你之前的SingleOrDefault逻辑一致 var user = query.SingleOrDefault();
另外还有两个小细节要注意:
- 你原来的原生SQL是要查询包含角色名的组合数据,所以别直接
select u,得像上面那样构造匿名对象(或者你可以专门建一个DTO类来接收这些字段),这样才能拿到和原SQL一致的返回结果。 - 用这种LINQ写法不仅解决了特殊字符导致的MySQL报错,还能彻底避免SQL注入风险——EF会自动帮你处理参数化查询,比用
String.Format拼SQL安全太多了。
内容的提问来源于stack exchange,提问作者yodellingbutters




