【发布时间】:2021-05-09 22:36:29
【问题描述】:
在 C# 中,我试图将 DataTable 作为参数传递给 SQL 语句。我的代码如下:
protected virtual void DoDeleteRecords(List<Guid> ids)
{
if (ids.Count > 0)
{
DataTable tvp = new DataTable();
tvp.Columns.Add("Id", typeof(Guid));
foreach (Guid id in ids)
{
DataRow row = tvp.NewRow();
row["Id"] = id;
tvp.Rows.Add(row);
}
string sql = string.Format("DELETE FROM MyTable WHERE ID IN ({0})", "@IDTable");
SqlConnection connection = new SqlConnection(CoreSettings.ConnectionString);
using (connection)
{
SqlCommand command = new SqlCommand(sql, connection);
SqlParameter tvpParam = command.Parameters.AddWithValue("@IDTable", tvp);
tvpParam.SqlDbType = SqlDbType.Structured;
tvpParam.TypeName = "dbo.IDList";
connection.Open();
command.ExecuteNonQuery();
connection.Close();
}
}
}
但是,当 command.ExecuteNonQuery 被调用时,我得到以下 SqlException 错误:
必须声明标量变量“@IDTable”
我了解此错误通常与丢失参数值有关,但据我所知,我知道。
谁能看出我做错了什么?
非常感谢。
更新我已经修改了问题以从我的示例中删除糟糕的 SQL 注入丰富的代码。
【问题讨论】:
-
您不能在 ad-hoc 语句中传递 TVP。这种方式仅支持存储过程参数。考虑使用 Dapper;这是无趣的样板,Dapper 确实支持构建列表。
-
啊,好的。那么这将解释它!谢谢@JeroenMostert
-
当
tableName是 TVP 时,"DELETE FROM " + tableName + " WHERE..." 还试图实现什么?这会在子句中注入一个标量值。此外,这种类型的语法是一种可怕的安全性漏洞。现在是 2021 年,SQL 注入应该在几年前就已经死了。 -
@JeroenMostert 那是垃圾,你当然可以。但是没有使用 TVP,OP 只是将一个列表直接连接到查询中。正确的代码是
"DELETE FROM " + tableName + " WHERE " + idColumnName + " IN (SELECT * FROM @IDTable)"不需要string.Format。无论如何,这段代码看起来很危险,对 SQL 注入完全开放 -
@Charlieface 你是绝对正确的。我错过了来自 IN 的 SELECT。该死的!感谢您发现这一点。为了清楚起见,这不是生产代码——只是我用来测试一些想法的东西。不,其中一个想法不是“如何将我的 SQL 注入到最大”!
标签: c# sql-server sqlcommand sqlexception table-valued-parameters