You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

SQL WHERE IN与List<string>配合失效问题排查

问题根源分析

你遇到的核心问题是误解了FromSqlRaw的参数作用:它的参数是用于参数化查询的,不是用来直接拼接SQL片段的。

当你把string.Join(",", allowedStatus.Select(s => "'" + s + "'"))作为第二个参数传入时,EF Core会把这个完整的字符串(比如'de')当作一个单一的参数值,而不是把它解析成IN子句里的选项。实际执行的SQL会变成这样:

SELECT computerimport.hostname FROM ComputerImport 
WHERE LOWER(SUBSTRING(computerimport.hostname, 1, 2)) IN (@p1) 
AND computerimport.hostname LIKE '%' + @p0 + '%'

其中@p1的值是'de'(包含单引号),这意味着你在查询**开头两个字符等于'de'(带引号)**的主机名,自然找不到符合条件的结果。

而你直接传入"DE"时能生效,是因为此时@p1的值是DE,LOWER(SUBSTRING(...))得到的de和DE在数据库的不区分大小写比较中匹配(取决于你的数据库配置),但这只是巧合,并不是正确的用法。


正确解决方案

方案1:动态构建参数化的IN子句(推荐,避免SQL注入)

我们需要为allowedStatus中的每个元素生成独立的参数占位符,然后把这些元素作为单独的参数传入:

string searchString = "";
List<string> allowedStatus = new List<string> { "de" };

// 为每个状态生成一个参数占位符(比如@p0, @p1...)
var statusPlaceholders = string.Join(", ", allowedStatus.Select((_, idx) => $"@status{idx}"));

// 构建包含所有参数占位符的SQL模板
string sqlQuery = @"
SELECT computerimport.hostname 
FROM ComputerImport 
WHERE LOWER(SUBSTRING(computerimport.hostname, 1, 2)) IN ({0}) 
AND computerimport.hostname LIKE '%' + @search + '%'";

// 替换IN子句的占位符,这里用string.Format是安全的,因为占位符是我们自己生成的
sqlQuery = string.Format(sqlQuery, statusPlaceholders);

// 准备参数列表:先加searchString,再加所有allowedStatus元素
var parameters = new List<object> { searchString };
parameters.AddRange(allowedStatus);

// 执行查询
var result = _context.OverviewQueries.FromSqlRaw(sqlQuery, parameters.ToArray());

方案2:使用FromSqlInterpolated(更简洁,自动参数化)

FromSqlInterpolated支持插值字符串,EF Core会自动把插值变量转换成参数,避免SQL注入:

string searchString = "";
List<string> allowedStatus = new List<string> { "de" };

// 安全生成参数化的IN子句占位符
var statusParams = allowedStatus.Select((s, idx) => (ParamName: $"@status{idx}", Value: s)).ToList();
var safeStatusInClause = string.Join(", ", statusParams.Select(p => p.ParamName));

// 构建安全的SQL模板
var safeSqlQuery = $@"
SELECT computerimport.hostname 
FROM ComputerImport 
WHERE LOWER(SUBSTRING(computerimport.hostname, 1, 2)) IN ({safeStatusInClause}) 
AND computerimport.hostname LIKE '%{searchString}%'";

// 执行查询,EF会自动处理参数化
var result = _context.OverviewQueries.FromSqlInterpolated(safeSqlQuery, statusParams.Select(p => p.Value));

关键注意点
  • 永远不要直接把用户输入拼接成SQL字符串(会导致SQL注入),参数化查询是必须的。
  • FromSqlRaw的参数是值参数,不是SQL片段的占位符,不能用来拼接SQL语法(比如IN子句的选项、表名等)。如果需要动态生成SQL语法部分,必须自己构建安全的模板字符串,再传入对应的参数。

内容的提问来源于stack exchange,提问作者Stephan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.07 22:57:33