我正在尝试使用ExecuteInterpolatedSqlAsync
执行一个查询,该查询检查整数数组中是否包含特定的子字符串。
我试过的是:
var value = "example";
var integers = new List<int> { 100, 404, 777 };
FormattableString query =
$"DELETE FROM Table1
WHERE Type = {value}
AND CAST(SUBSTRING(Value, 5, 7) AS INTEGER) IN ({string.Join(",", integers)})";
await _signInDbContext.ExecuteSqlInterpolatedAsync(query);
当我调试它时,它显示如下字符串:
DELETE FROM Table1 WHERE Type = example AND CAST(SUBSTRING(Value, 5, 7) AS INTEGER) IN (100,404,700)
但当它对数据库运行查询时,它会在两个参数周围加引号:
DELETE FROM Table1 WHERE Type = 'example' AND CAST(SUBSTRING(Value, 5, 7) AS INTEGER) IN ('100,404,700')
这是有道理的,因为两者都是一个字符串。但这不是我想要的(显然(,我得到了这个错误:
将nvarchar值"100404777"转换为数据类型int 时转换失败
如何在此ExecuteSqlInterpolatedAsync
查询中包含整数数组?
相信在SQL中,您需要STRING_SPLIT
使用分隔符,
解析的值,然后将value
强制转换为INTEGER
string integerStr = string.Join(",", integers);
FormattableString query =
$"DELETE FROM Table1
WHERE Type = {value}
AND CAST(SUBSTRING(Value, 5, 7) AS INTEGER)
IN (SELECT CAST(value AS INTEGER) FROM STRING_SPLIT({integerStr}, ','))";
SQL
DELETE FROM Table1
WHERE Type = @value
AND CAST(SUBSTRING(Value, 5, 7) AS INTEGER)
IN (SELECT CAST(value AS INTEGER) FROM STRING_SPLIT('100,404,777', ','))
更新:遗漏了字符串串联无法正常工作的原因解释
根据通过参数,
虽然此语法看起来像String.Format语法,但提供的值被包装在DbParameter中,生成的参数名称插入到指定{0}占位符的位置。
该值作为DbParameter
作为传递给查询
DELETE FROM Table1
WHERE Type = @value
AND CAST(SUBSTRING(Value, 5, 7) AS INTEGER) IN (@P1)
因此,最后的查询将看起来像:
DELETE FROM Table1
WHERE Type = @value
AND CAST(SUBSTRING(Value, 5, 7) AS INTEGER) IN ('100,404,700')
这里的real解决方案是使用表值参数
首先,在SSMS中创建一个表类型。为此,我通常保留一些标准的一列和两列类型。
CREATE TYPE dbo.IntList (value int PRIMARY KEY);
然后像这个一样使用它
var value = "example";
var integers = new List<int> { 100, 404, 777 };
var table = new DataTable { Columns = {
{"value", typeof(int)},
} };
foreach (var v in integers)
table.Rows.Add(v);
var tableParam = new SqlParameter("@tbl", SqlDbType.Structured)
{
TypeName = "dbo.IntList",
Value = table,
};
FormattableString query = $@"
DELETE FROM Table1
WHERE Type = {value}
AND CAST(SUBSTRING(Value, 5, 7) AS INTEGER) IN
(SELECT value FROM {tableParam})";
await _signInDbContext.ExecuteSqlInterpolatedAsync(query);
// alternately use Raw
const string query = @"
DELETE FROM Table1
WHERE Type = {0}
AND CAST(SUBSTRING(Value, 5, 7) AS INTEGER) IN
(SELECT value FROM {1})";
await _signInDbContext.ExecuteSqlRawAsync(query, value, tableParam);