将表值参数传递给参数化 SQL 语句时出现“必须声明标量变量”错误

问题描述

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

解决方法

首先:我不知道您从哪里获得 tableNamecolumnName,但如果它们是用户提供的,那么这对 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();
    }
}

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...