问题描述
在 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 注入丰富的代码。
解决方法
首先:我不知道您从哪里获得 tableName
和 columnName
,但如果它们是用户提供的,那么这对 SQL 注入是开放的。至少,使用 QUOTENAME()
确保没有注入实际代码。
其次,您实际上并未使用 TVP。您拥有的代码只是说 IN (@IDTable)
这不是您使用 TVP 的方式。
TVP 只是一个表变量,应该像任何其他表一样使用:
protected virtual void DoDeleteRecords(List<Guid> ids)
{
if (ids.Count == 0)
return;
DataTable tvp = new DataTable();
tvp.Columns.Add("Id",typeof(Guid));
foreach (Guid id in ids)
tvp.Rows.Add(id);
const string sql = @"
DELETE FROM table
WHERE idColumnName IN (SELECT * FROM @IDTable);
";
using(SqlConnection connection = new SqlConnection(CoreSettings.ConnectionString))
using(SqlCommand command = new SqlCommand(sql,connection))
{
command.Parameters.Add(
new SqlParameter("@IDTable",SqlDbType.Structured)
{
Value = tvp,Direction = ParameterDirection.Input,TypeName = "dbo.IDList"
});
connection.Open();
command.ExecuteNonQuery();
}
}