SqlBulkCopy drops global temp table 然后无法执行插入

SqlBulkCopy drops global temp table then fails to perform insert

我使用 SqlBulkCopy 以非常快速有效的方式填充 table。以前,我用“临时名称”(类似于 Temp_1239128213129873912873 的名称)创建了永久 tables,但它总是困扰着我。尽管显然是一个临时 table 事实上的,但它在法律上仍然是一个永久的 table,因此从技术上讲它是生产中的模式修改。此外,如果进程崩溃,清理代码不会 运行 并且这些 table 会保留;一年后,会累积5-6个这样的。

我决定尝试切换到全局温度 tables。当我这样做时,我开始面临这个奇怪的问题,即对 WriteToServerAsync 的调用报告未找到 table,并出现诸如“无法访问目标 table '##temp_123871298371928739182739'"

string connStr = "...";
using var sqlConnection = new SqlConnection(connStr); await sqlConnection.OpenAsync();
using var com = new SqlCommand(sqlConnection) { CommandText = "CREATE TABLE ##temp_123871298371928739182739 (...);" }; await com.ExecuteNonQueryAsync();

var sqlBulkCopy = new SqlBulkCopy(connStr) { DestinationTableName = "##temp_123871298371928739182739", };
await sqlBulkCopy.WriteToServerAsync(sourceDataReader); // throws exception

当我调试它时,发现 table 已成功创建,但不知何故被丢弃在该方法中。我尝试在 SQL UI(MSSQL 的 SSMS)中创建相同的 table,并且 WriteToServerAsync 工作正常。这让我相信这与从连接池中重用时 SqlConnection 被重置有关。

为了解决这个问题,我为全局临时 table 创建和 WriteToServerAsync 调用保持了相同的 SqlConnection,它工作得很好(SQL 服务器和 Azure SQL):

string connStr = "...";
using var sqlConnection = new SqlConnection(connStr); await sqlConnection.OpenAsync();
using var com = new SqlCommand(sqlConnection) { CommandText = "CREATE TABLE ##temp_123871298371928739182739 (...);" }; await com.ExecuteNonQueryAsync();
var sqlBulkCopy = new SqlBulkCopy(sqlConnection) { DestinationTableName = "##temp_123871298371928739182739", };
await sqlBulkCopy.WriteToServerAsync(sourceDataReader);

问题是一旦连接关闭临时 tables 就会被丢弃,所以你需要保持它打开直到你完成 table。

您还应该最好避免 ## 全局临时 tables,因为它们会干扰使用相同名称的其他连接。而是使用 # 本地温度 tables.

我注意到您的代码没有 using 块。它真的应该是这样的:

using (var sqlConnection = new SqlConnection("..."))
{
    await sqlConnection.OpenAsync();
    using (var com = new SqlCommand(sqlConnection) { CommandText = "CREATE TABLE #temp (...);" })
    {
         await com.ExecuteNonQueryAsync();
    }

    using (var sqlBulkCopy = new SqlBulkCopy(sqlConnection) { DestinationTableName = "#temp", })
    {
        await sqlBulkCopy.WriteToServerAsync(sourceDataReader);
    }

    // other stuff with temp table

    sqlConnection.Close();   // table is dropped automatically
}