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
}
我使用 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
}