'Must Declare the Scalar Variable' 将 Table 值参数传递给参数化 SQL 语句时出错
'Must Declare the Scalar Variable' Error When Passing a Table-Valued Parameter to a Parameterized SQL Statement
在 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 错误:
Must declare the scalar variable "@IDTable"
我知道这个错误通常与丢失参数值有关,但据我所知,我知道。
谁能看出我做错了什么?
非常感谢。
更新 我已经修改了问题以从我的示例中删除糟糕的 SQL 注入丰富的代码。
第一件事:我不知道你从哪里得到 tableName
和 columnName
,但如果它们是用户提供的,那么这对 SQL 注入是开放的。至少,使用 QUOTENAME()
以确保没有注入实际代码。
其次,您实际上并没有使用TVP。你的代码只是说 IN (@IDTable)
这不是你使用 TVP 的方式。
TVP 只是一个 table 变量,应该像其他任何变量一样使用 table:
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();
}
}
在 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 错误:
Must declare the scalar variable "@IDTable"
我知道这个错误通常与丢失参数值有关,但据我所知,我知道。
谁能看出我做错了什么?
非常感谢。
更新 我已经修改了问题以从我的示例中删除糟糕的 SQL 注入丰富的代码。
第一件事:我不知道你从哪里得到 tableName
和 columnName
,但如果它们是用户提供的,那么这对 SQL 注入是开放的。至少,使用 QUOTENAME()
以确保没有注入实际代码。
其次,您实际上并没有使用TVP。你的代码只是说 IN (@IDTable)
这不是你使用 TVP 的方式。
TVP 只是一个 table 变量,应该像其他任何变量一样使用 table:
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();
}
}