'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 注入丰富的代码。

第一件事:我不知道你从哪里得到 tableNamecolumnName,但如果它们是用户提供的,那么这对 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();
    }
}