EF Core 8 + SQL Server:Contains() 突然报 “关键字 WITH 附近有语法错误“?
2026/6/10 8:29:10 网站建设 项目流程

最近遇到一个EF Core 查询的问题,想跟大家分享下,应该有很多小伙伴已经遇到过了。

升级到 .NET 8 / EF Core 8 后,原来跑得好好的 Where(x => ids.Contains(x.id)) 突然炸了,日志里赫然写着:关键字 'WITH' 附近有语法错误。如果此语句是公用表表达式,那么前一个语句必须以分号结尾。 ——这篇文章帮你搞清楚为什么、怎么修、以后怎么写才不踩坑。

1. 先看症状

假设你有这样一段再普通不过的代码:

var ids = new List<int> { 1, 2, 3, 5, 8 }; var users = await _db.sys_admin     .Where(x => ids.Contains(x.id))     .ToListAsync();

在 EF Core 6/7 上完全正常。升级到 EF Core 8 后,同样的代码报:

Microsoft.Data.SqlClient.SqlException (0x80131904): 关键字 'WITH' 附近有语法错误。 如果此语句是公用表表达式、xmlnamespaces 子句或者更改跟踪上下文子句, 那么前一个语句必须以分号结尾。

关键词:WITH分号公用表表达式(CTE)。SQL Server 错误号为 156。

2. 根因:EF Core 8 对 Contains 的翻译方式变了

这不是 Bug,这是 EF Core 8 的一个 有意为之的 Breaking Change(官方文档明确定义为 High Impact)。

2.1 旧行为(EF Core 6/7)

EF 把参数化列表的值内联为 SQL 常量

-- EF Core 7 生成的 SQL SELECT [s].[id], [s].[username], ... FROM [sys_admin] AS [s] WHERE [s].[id] IN (1, 2, 3, 5, 8)

简单直接,没有 CTE,没有任何问题——直到你开始关注查询计划缓存。

2.2 新行为(EF Core 8)

EF Core 8 不再内联常量,而是通过 OPENJSON 或 CTE(公用表表达式) 来传递参数化集合。简化后的生成逻辑是:

简单值列表(string/int 常量)→ OPENJSON 方式 复杂查询 / 多次 Contains → CTE(WITH ... AS)方式

对于 ids.Contains(x.id) 这类场景,EF 可能生成类似这样的 SQL:

-- EF Core 8 可能生成的 SQL(简化版) ;WITH [t] AS (     SELECT [v].[value] FROM OPENJSON(@__ids_0) ... ) S

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询