通过 SqlDataRecord 将多行导入到 SQL Server 的一次往返中的临时表中

问题描述 投票:0回答:1

所以这个问题才刚刚开始出现在分析器中。

我们有一些看起来像这样的东西。

   using (var cmd = connection.CreateCommand()) {
       cmd.CommandText = "INSERT INTO #Ids VALUES (@0);";
       cmd.Parameters.Add(cmd.CreateParameter() { ParameterName = "@0", DbType = DbType.Integer });
       cmd.Prepare();
       foreach (var value in values)
       {
          ((IDbDataParameter)cmd.Parameters[0]).Value = value;
          cmd.ExecuteNonQuery();
       }
    }

我们正在研究通过减少往返次数来加快这一速度的可能性。在这里使用 DataTable 会是一个怪物,但有一种类型

SqlDataRecord
似乎很合适,所以我们应该能够做这样的事情:

   using (var cmd = connection.CreateCommand()) {
       cmd.CommandText = "INSERT INTO #Ids SELECT * FROM @0;";
       var param  = cmd.CreateParameter();
       param.ParameterName = "@0";
       // FIXME more properties
       cmd.Parameters.Add(param);
       param.Value = values.Cast<int>().Select((x) => {
           // FIXME Create new SqlDataRecord
       }.ToList();
       cmd.ExecuteNonQuery();
    }

我在哪里找不到 API 的示例,也不知道如何使用它。由于 SqlClient 中的类型无意义,普通的 Visual Studio Intellisense 是无用的。

如何填写上面的 FIXME 注释?

相关问题,没有好的答案:当我有一大堆 ID 时,如何在 SQL Server 中创建临时表

评论中有人要求了解更大的情况。确实没有一个很好的方法可以通过缩小这里来获取更多信息。代码库中只有一份例程为所有 SQL 调用(即存储过程)设置参数,就是这个。

行数的比例因子是肥尾的;平均行数小于 10,但最大大小非常大,并且经常发生超过 1000 行的调用。因此我们加载一个临时表;在转换为执行

foreach
循环以外的操作时,我们仍然加载临时表。

明天我需要检查如何从.net代码将表值参数传递到存储过程是否是一个有效的欺骗目标。

c# sqlclient
1个回答
0
投票

一个完整的工作示例。

using var connection = new SqlConnection(@"...");
connection.Open();
int[] values = [1, 2, 3, 4, 5];

using (var cmd = connection.CreateCommand())
{
    cmd.CommandText = "CREATE TYPE dbo.Ids AS TABLE (Id INT );";
    cmd.ExecuteNonQuery();    
}

using (var cmd = connection.CreateCommand())
{
    cmd.CommandText = "CREATE TABLE #Ids (Id INT);";
    cmd.ExecuteNonQuery();    
}

using (var cmd = connection.CreateCommand())
{
    cmd.CommandText = "INSERT INTO #Ids SELECT * FROM @0;";

    var param = cmd.CreateParameter();
    param.ParameterName = "@0";
    param.SqlDbType = SqlDbType.Structured;
    param.TypeName = "dbo.Ids";

    cmd.Parameters.Add(param);

    var record = new SqlDataRecord(new SqlMetaData("Id", SqlDbType.Int));

    param.Value = values.Cast<int>()
        .Select(x =>
        {
            //var record = new SqlDataRecord(new SqlMetaData("Id", SqlDbType.Int));
            record.SetInt32(0, x);
            return record;
        })
        //.ToList()
        ;

    var affectedRows = cmd.ExecuteNonQuery();
    Console.WriteLine($"Rows inserted: {affectedRows}");
}

using (var cmd = connection.CreateCommand())
{
    cmd.CommandText = "SELECT COUNT(*) FROM #Ids;";
    var count = cmd.ExecuteScalar();
    Console.WriteLine($"Count: {count}");
}
© www.soinside.com 2019 - 2024. All rights reserved.