【问题标题】:SqlBulkCopy drops global temp table then fails to perform insertSqlBulkCopy 删除全局临时表然后无法执行插入
【发布时间】:2021-08-16 20:55:26
【问题描述】:

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

我决定尝试切换到全局临时表。当我这样做时,我开始遇到这个奇怪的问题,调用WriteToServerAsync 报告找不到表,并出现诸如“无法访问目标表'##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

【问题讨论】:

标签: c# .net sql-server azure-sql-database


【解决方案1】:

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

为了解决这个问题,我为全局临时表创建和 WriteToServerAsync 调用保留了相同的 SqlConnection,它可以完美运行(SQL Server 和 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);

【讨论】:

    【解决方案2】:

    问题在于,一旦连接关闭,临时表就会被删除,因此您需要将其保持打开状态,直到完成表。

    理想情况下,您还应该避免使用## 全局临时表,因为它们会干扰使用相同名称的其他连接。而是使用 # 本地临时表。

    我注意到您的代码没有 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
    }
    

    【讨论】:

    • 我编辑了我的问题和答案,以澄清我仍在使用随机发生器来防止全局临时表冲突。本地临时表不可用,因为它们是特定于范围的; CREATE 脚本执行,然后本地 #temp 表被删除,not 在连接关闭时。你的回答在这方面是不正确的。
    猜你喜欢
    • 2011-12-17
    • 2010-12-07
    • 1970-01-01
    • 2015-12-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-07-21
    相关资源
    最近更新 更多