EF Core 支持查询中使用变量并自动参数化,避免 SQL 注入;需警惕循环中闭包捕获导致的值错误;复杂逻辑应使用可翻译表达式或 PredicateBuilder。
EF Core 在查询中使用变量是完全支持的,但要注意“闭包捕获”(closure capture)的行为——它不是 EF Core 特有,而是 C# 委托/表达式树机制的一部分。关键在于:EF Core 会把变量值“捕获”进表达式树并翻译成 SQL 参数,而不是在运行时动态拼接 SQL。
只要变量在 LINQ 查询中被直接引用(如 Where(x => x.Name == name)),EF Core 会识别该变量并将其作为参数传入生成的 SQL,避免 SQL 注入,也利于查询计划缓存。
→ 生成类似 WHERE [u].[Name] LIKE @__keyword_0 的 SQL,keyword 作为参数传入。
这是最常见陷阱:用 for 或 foreach 循环构建多个查询时,若变量未及时“快照”,所有查询可能都使用循环结束时的最终值。
EF Core 只能翻译已知函数和属性访问。如果变量是自定义方法返回值、或调用非可翻译方法(如 DateTime.Now.AddDays(1)),EF Core 会尝试在客户端执行(触发客户端评估警告或异常)。
DateTime.UtcNow.AddDays(1)(EF Core 支持)someDate.ToUniversalTime()(多数版本不支持,会降级到客户端)ConfigureWarnings(w => w.Throw(RelationalEventId.QueryClientEvaluationWarning)) 可捕获隐式客户端评估不要拼字符串,也不要滥用 if 块重复写整个查询。可用 Expression 组合,或借助开源库如 LinqKit 的 PredicateBuilder。
基本上就这些。核心原则:信任 EF Core 对简单变量的参数化处理,但
对循环变量、复杂计算和动态逻辑保持清醒——不是所有 C# 代码都能进 SQL。