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

问题描述 投票: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 智能感知毫无用处。

如何填写上面的 FIXME 注释?

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

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

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

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

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

c# sql-server sqlclient
1个回答
1
投票

一个完整的工作示例。

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.