Where链式调用不立即执行,仅构建表达式树;EF Core会合并为单条SQL的WHERE AND语句;需避免循环中多次ToList()导致N次查询;注意null安全与日期范围查询的时分秒问题。

Where 链式调用能直接拼条件,但要注意执行时机
多数场景下,不需要手写表达式树——Where 多次链式调用就足够了。EF Core 会把连续的 Where 合并成一个 SQL 的 WHERE ... AND ... AND ...,不是多次查询。
常见错误是误以为“每次 Where 都触发一次数据库访问”:只要没调用 ToList()、FirstOrDefault() 或 Count() 这类终结方法,它只是构建表达式树,不会执行。
- 正确写法:
var query = context.Users.AsQueryable(); if (!string.IsNullOrEmpty(name)) query = query.Where(x => x.Name.Contains(name)); if (age > 0) query = query.Where(x => x.Age == age); var result = query.ToList(); - 错误写法:在循环里反复调用
query.Where(...).ToList(),导致 N 次全表扫描 - 注意 null 安全:EF Core 能翻译
x.Name != null && x.Name.Contains("a"),但不支持x.Name?.Contains("a") == true(部分版本抛NotSupportedException)
Expression.AndAlso 是组合表达式树的底层方式,别过早优化
当你需要把多个 Expression<func bool>></func> 合并成一个可复用、可缓存、可传递的表达式时,才用 Expression.AndAlso。它不是语法糖,而是绕过编译器自动推导、手动构造表达式树的过程。
典型坑点:参数引用必须一致。两个表达式如果用了不同 ParameterExpression,AndAlso 会报错或生成无效树。
- 必须共用同一个
ParameterExpression,比如var p = Expression.Parameter(typeof(User), "u"); - 不能直接
Expression.AndAlso(expr1, expr2),要拆出.Body并重绑定参数:Expression.AndAlso(Expression.Invoke(expr1, p), Expression.Invoke(expr2, p)),或者用更稳妥的Expression.Lambda(..., p)封装 - 编译后得到
Func<T, bool>,只能用于内存集合;若需数据库翻译,必须保持为Expression<Func<T, bool>>并传给IQueryable.Where()
SQL 字符串拼接仍常见,但必须用参数化防止注入
纯 ADO.NET 场景下,动态 WHERE 条件仍常靠字符串拼接,但绝不能拼值——所有用户输入必须走 SqlParameter。
错误示范:sql += " AND Name = '" + name + "'"; —— 直接暴露 SQL 注入风险。
- 正确做法:用
List<SqlParameter>收集参数,string.Join(" AND ", conditions)拼条件片段,最后统一传参 - 模糊查询记得手动加通配符:
new SqlParameter("@name", "%" + name + "%"),而不是在 SQL 里写LIKE '%@name%' - 空条件判断要清晰:先收集所有可能条件到
List<string>,再检查.Count > 0决定是否追加WHERE
EF Core 中日期范围查询容易漏掉时分秒
前端选“2026-04-21”,后端直接 db.Orders.Where(x => x.OrderDate == date) 几乎永远查不到数据,因为数据库里存的是带时间的 DateTime。
真正要的是“当天内所有订单”,得转成范围比较:
- 安全写法:
var start = date.Date; var end = start.AddDays(1); query = query.Where(x => x.OrderDate >= start && x.OrderDate - 避免用
EntityFunctions.TruncateTime()(已弃用)或EF.Functions.DateDiffDay()(可读性差、索引不友好) - 如果字段是
date类型(无时间),EF Core 通常能正确映射;但一旦是datetime2,就必须按范围处理
Where 更直白、更少出错;只有当你需要运行时决定是否启用某段条件、或要把查询逻辑封装成可配置规则时,才值得碰 Expression。


















