We have an API in our software that does bulk imports of data to a temporary table and subsequently issues a MERGE statement using the populated temporary table. The implementation of the API (with the important parts quoted below) works perfectly using
SQL Server 2008 SP2+, but we recently discovered that our implementation is causing problems when running our software on Windows Azure (and SQL Azure).
Reported exception messages are as follows:
- System.InvalidOperationException: Cannot access destination table '#Contacts'
- System.Data.SqlClient.SqlException: Reference to database and/or server name in 'tempdb..sp_tablecollations_100' is not supported in this version of SQL Server.
We're fairly sure the following C# statement raises the exception:
bulk.WriteToServer(table);
Here's more complete listing of the implementation that contains the above line:
var table = new DataTable();
table.Columns.Add(new DataColumn("Id", typeof(Guid)));
table.Columns.Add(new DataColumn("Status", typeof(int)));
foreach (var contact in enumerable)
{
var row = table.NewRow();
row["Id"] = contact.Id;
row["Status"] = (int) contact.EmailValidationStatus;
table.Rows.Add(row);
}
using (var scope = new TransactionScope(TransactionScopeOption.Required, TransactionOptions))
{
using (var connection = this.CreateSqlConnection())
{
connection.Open();
var command = new SqlCommand("CREATE TABLE #Contacts (Id UNIQUEIDENTIFIER, Status INT)", connection);
command.ExecuteNonQuery();
//BulkCopy the data in the DataTable to the temp table
using (var bulk = new SqlBulkCopy(connection))
{
bulk.BulkCopyTimeout = 0;
bulk.DestinationTableName = "#Contacts";
bulk.WriteToServer(table);
}
command.CommandText = "MERGE INTO dbo.[Contact] AS Target " +
"USING #Contacts AS Source " +
"ON Target.Id = Source.Id " +
"WHEN MATCHED THEN UPDATE SET Target.EmailValidationStatus = @status;";
command.Parameters.Add(new SqlParameter("@status", (int) status));
command.ExecuteNonQuery();
//Clean up the temp table
command.CommandText = "DROP TABLE #Contacts";
command.ExecuteNonQuery();
scope.Complete();
}
}
In order to verify that the DDL statement for creating the temporary table is valid, I opened SSMS against the SQL Azure database in question and executed the following statement (which completed succesfully).
CREATE TABLE #Contacts (Id UNIQUEIDENTIFIER, Status INT)
DROP TABLE #Contacts
Unless there are differences in scoping semantics between SQL Server 2008 SP2+ and SQL Azure, the temporary table is created with a local scope (i.e. to the explicitly managed connection).
Is this as simple as stating that SqlBulkCopy doesn't support temporary tables on SQL Azure?
Anders Borum / SphereWorks