将用户定义的 table 传递给 SqlCommand(不执行存储过程)

Pass a user defined table to a SqlCommand (which doesn't execute a stored procedure)

我正在尝试将用户定义的 table 与简单的 SqlCommand(不执行存储过程)结合使用。
我收到消息 Must declare the scalar variable,尽管参数已经定义。

代码(假设accountIds在别处定义,所以dtAccountIds有一些值):

var sqlCommand = new SqlCommand(); 
sqlCommand.CommandText =
@"SELECT * INTO #RecordsToLog
    FROM Accounts
    WHERE [AccountId] IN (@AccountIds)";

var dtAccountIds = new DataTable();
dtAccountIds.Columns.Add("id", typeof(int));
accountIds.ToList().ForEach(id => dtAccountIds.Rows.Add(id));
sqlCommand.Parameters.AddWithValue("@AccountIds", dtAccountIds).TypeName = "dbo.IdsTable";

sqlCommand.ExecuteNonQuery();

用户定义的 table 创建于:

CREATE TYPE [dbo].[IdsTable] AS TABLE([id] [int] NULL)

我应该怎么做才能解决这个问题?

您必须将参数配置为SqlDbType.Structured。避免使用 AddWithValue,让我建议这个符号:

SqlParameter param = new SqlParameter("@AccountIds", SqlDbType.Structured, 0)
{
    Value = dtAccountIds
}

根据 MS-DOCS 关于 SqlDbType Enum:

Structured = A special data type for specifying structured data contained in table-valued parameters.

首先,你的SQL代码是错误的。 table参数是一个table变量,所以你需要一个完整的子查询IN (SELECT id FROM @AccountIds).

为什么要插入临时文件 table,我不知道,你没有给我们任何上下文。

接下来,you shouldn't use AddWithValue 改为声明确切的类型 SqlDbType.Structured,以及 DirectionTypeName

此外,希望您没有缓存连接对象。 您必须释放连接和命令对象。

const string query = @"
SELECT *
INTO #RecordsToLog
    FROM Accounts
    WHERE [AccountId] IN
      (SELECT id FROM @AccountIds)
";

using (var sqlCommand = new SqlCommand(query, connection))
{
    var dtAccountIds = new DataTable { Columns = { { "id", typeof(int) } } };
    foreach (var id in accountIds)
        dtAccountIds.Rows.Add(id);
    sqlCommand.Parameters.Add(new SqlParameter("@AccountIds", SqlDbType.Structured)
        {
            Value = dtAccountIds,
            TypeName = "dbo.IdsTable",
            Direction = ParameterDirection.Input
        });

    sqlCommand.ExecuteNonQuery();
}