LINQ 查询关键在于正确区分 IEnumerable 与 IQueryable、合理选用 Where/First/Single 及其 OrDefault 变体、避免 N+1 查询、按场景选择查询表达式或方法语法,并警惕延迟执行陷阱如重复 Count() 调用。
LINQ 查询不是“用不用”的问题,而是“怎么用对、用稳、用得明白”的问题。它本质是一套统一的查询语法和方法集,核心在于理解 IEnumerable 和 IQueryable 的区别,以及何时该用方法语法、何时该用查询表达式。
什么时候该用 Where 而不是 First 或 Single
这是最常混淆的起点:三者都做筛选,但语义和异常行为完全不同。
-
Where返回所有匹配项(IEnumerable),安全、可链式调用,适合后续继续处理 -
First返回第一个匹配项,没找到抛InvalidOperationException;加OrDefault版本(FirstOrDefault)则返回default(T)(如null或0) -
Single要求**有且仅有一个**匹配项,多于一个或零个都抛异常;SingleOrDefault仅在零个时返回默认值,多个仍报错
典型误用:用 Single 查用户列表中邮箱匹配的记录——一旦数据库有脏数据(重复邮箱),线上直接崩溃。应优先用 FirstOrDefault,再显式判断是否为 null。
IQueryable 和 IEnumerable 混用导致 N+1 查询
EF Core / NHibernate 等 ORM 中,IQueryable 是“可翻译的表达式树”,而 IEnumerable 是“内存集合”。一旦调用 ToList()、ToArray() 或任何强制执行的方法,查询就落地了。
- 错误写法:
var users = context.Users.ToList(); // 已加载全部用户到内存 var activeOrders = users.Where(u => u.IsActive).SelectMany(u => u.Orders).ToList(); // N+1:每用户查一次 Orders
- 正确写法:
var activeOrders = context.Users .Where(u => u.IsActive) .SelectMany(u => u.Orders) .ToList(); // 整个表达式由 EF 转成一条 SQL
关键判断点:看变量声明类型。如果变量是 IQueryable,且没被中间调用过 AsEnumerable() 或强制执行方法,那它还在“可翻译”状态。