Not
Åtkomst till denna sida kräver auktorisation. Du kan prova att logga in eller byta katalog.
Åtkomst till denna sida kräver auktorisation. Du kan prova att byta katalog.
Masskopieringsåtgärder kan utföras som isolerade åtgärder eller som en del av en transaktion i flera steg. Med det här senare alternativet kan du utföra mer än en masskopieringsåtgärd inom samma transaktion, samt utföra andra databasåtgärder som infogningar, uppdateringar och borttagningar, samtidigt som du kan checka in eller återställa hela transaktionen.
Som standard utförs en masskopieringsåtgärd som en isolerad åtgärd. Masskopieringsåtgärden sker på ett icke-transakterat sätt, utan möjlighet att återställa den. Om du behöver återställa hela eller delar av masskopian när ett fel inträffar kan du:
Använd en SqlBulkCopy-hanterad transaktion
Utför masskopieringsåtgärden i en befintlig transaktion
Registrera i ett System.TransactionsTransaction.
Utföra en masskopiering utan transaktion
Följande konsolprogram visar vad som händer när en icke-transaktionell masskopiering stöter på ett fel halvvägs genom åtgärden.
I exemplet innehåller källtabellen och måltabellen var och en Identity kolumn med namnet ProductID. Koden förbereder först måltabellen genom att ta bort alla rader och sedan infoga en enskild rad vars ProductID- är känd för att finnas i källtabellen. Som standard genereras ett nytt värde för kolumnen Identity i måltabellen för varje rad som läggs till. I detta exempel ställer man in ett alternativ vid öppning av anslutningen, vilket tvingar massinläsningsprocessen att istället använda de Identity-värdena från källtabellen.
Masskopieringsåtgärden körs med egenskapen BatchSize inställd på 10. När operationen stöter på den ogiltiga raden utlöses ett undantag. I det första exemplet är masskopieringsåtgärden icke-transaktionsbaserad. Alla batcher som kopieras fram till tidpunkten för felet har åtagits. Batchen som innehåller dubblettnyckeln återställs och masskopieringsåtgärden stoppas innan den bearbetar eventuella återstående batchar.
Anmärkning
Det här exemplet körs inte om du inte har skapat arbetstabellerna enligt beskrivningen i inställning av masskopieringsexempel. Den här koden tillhandahålls för att demonstrera syntaxen för att endast använda SqlBulkCopy. Om käll- och måltabellerna finns i samma SQL Server-instans är det enklare och snabbare att använda en Transact-SQL- INSERT ... SELECT-instruktion för att kopiera data.
using Microsoft.Data.SqlClient;
class Program
{
static void Main()
{
string connectionString = GetConnectionString();
// Open a sourceConnection to the AdventureWorks database.
using (SqlConnection sourceConnection =
new SqlConnection(connectionString))
{
sourceConnection.Open();
// Delete all from the destination table.
SqlCommand commandDelete = new SqlCommand();
commandDelete.Connection = sourceConnection;
commandDelete.CommandText =
"DELETE FROM dbo.BulkCopyDemoMatchingColumns";
commandDelete.ExecuteNonQuery();
// Add a single row that will result in duplicate key
// when all rows from source are bulk copied.
// Note that this technique will only be successful in
// illustrating the point if a row with ProductID = 446
// exists in the AdventureWorks Production.Products table.
// If you have made changes to the data in this table, change
// the SQL statement in the code to add a ProductID that
// does exist in your version of the Production.Products
// table. Choose any ProductID in the middle of the table
// (not first or last row) to best illustrate the result.
SqlCommand commandInsert = new SqlCommand();
commandInsert.Connection = sourceConnection;
commandInsert.CommandText =
"SET IDENTITY_INSERT dbo.BulkCopyDemoMatchingColumns ON;" +
"INSERT INTO " + "dbo.BulkCopyDemoMatchingColumns " +
"([ProductID], [Name] ,[ProductNumber]) " +
"VALUES(446, 'Lock Nut 23','LN-3416');" +
"SET IDENTITY_INSERT dbo.BulkCopyDemoMatchingColumns OFF";
commandInsert.ExecuteNonQuery();
// Perform an initial count on the destination table.
SqlCommand commandRowCount = new SqlCommand(
"SELECT COUNT(*) FROM dbo.BulkCopyDemoMatchingColumns;",
sourceConnection);
long countStart = System.Convert.ToInt32(
commandRowCount.ExecuteScalar());
Console.WriteLine("Starting row count = {0}", countStart);
// Get data from the source table as a SqlDataReader.
SqlCommand commandSourceData = new SqlCommand(
"SELECT ProductID, Name, ProductNumber " +
"FROM Production.Product;", sourceConnection);
SqlDataReader reader = commandSourceData.ExecuteReader();
// Set up the bulk copy object using the KeepIdentity option.
using (SqlBulkCopy bulkCopy = new SqlBulkCopy(
connectionString, SqlBulkCopyOptions.KeepIdentity))
{
bulkCopy.BatchSize = 10;
bulkCopy.DestinationTableName =
"dbo.BulkCopyDemoMatchingColumns";
// Write from the source to the destination.
// This should fail with a duplicate key error
// after some of the batches have been copied.
try
{
bulkCopy.WriteToServer(reader);
}
catch (Exception ex)
{
// Print the number of rows processed using the
// RowsCopied property.
Console.WriteLine("{0} rows were processed.",
bulkCopy.RowsCopied);
Console.WriteLine(ex.Message);
}
finally
{
reader.Close();
}
}
// Perform a final count on the destination
// table to see how many rows were added.
// Note that for this scenario, the value will
// not be equal to the RowsCopied property.
long countEnd = System.Convert.ToInt32(
commandRowCount.ExecuteScalar());
Console.WriteLine("Ending row count = {0}", countEnd);
Console.WriteLine("{0} rows were added.", countEnd - countStart);
Console.WriteLine("Press Enter to finish.");
Console.ReadLine();
}
}
private static string GetConnectionString()
// To avoid storing the sourceConnection string in your code,
// you can retrieve it from a configuration file.
{
return "Data Source=(local); " +
" Integrated Security=true;" +
"Initial Catalog=AdventureWorks;";
}
}
Utföra en dedikerad masskopieringsåtgärd i en transaktion
Som standard är en masskopieringsåtgärd en egen transaktion. När du vill utföra en dedikerad masskopieringsåtgärd skapar du en instans av SqlBulkCopy med en anslutningssträng eller använder ett befintligt SqlConnection objekt utan en aktiv transaktion. Masskopieringsoperationen skapar en transaktion i varje scenario och genomför eller återkallar sedan transaktionen.
Du kan uttryckligen ange UseInternalTransaction-alternativet i konstruktorn för SqlBulkCopy-klassen för att köra en masskopieringsåtgärd i en egen transaktion. Varje batch av åtgärden körs inom en separat transaktion.
Anmärkning
Eftersom olika batchar körs i olika transaktioner, om ett fel inträffar under masskopieringsåtgärden, återställs alla rader i den aktuella batchen, men rader från tidigare batchar kommer att finnas kvar i databasen.
Följande konsolprogram liknar föregående exempel, med ett undantag: I det här exemplet hanterar masskopieringsåtgärden sina egna transaktioner. Alla batcher som kopieras fram till tidpunkten för felet har åtagits. Batchen som innehåller dubblettnyckeln återställs och masskopieringsåtgärden stoppas innan den bearbetar eventuella återstående batchar.
Viktigt!
Det här exemplet körs inte om du inte har skapat arbetstabellerna enligt beskrivningen i inställning av masskopieringsexempel. Den här koden tillhandahålls för att demonstrera syntaxen för att endast använda SqlBulkCopy. Om käll- och måltabellerna finns i samma SQL Server-instans är det enklare och snabbare att använda en Transact-SQL-instruktion INSERT ... SELECT för att kopiera data.
using Microsoft.Data.SqlClient;
class Program
{
static void Main()
{
string connectionString = GetConnectionString();
// Open a sourceConnection to the AdventureWorks database.
using (SqlConnection sourceConnection =
new SqlConnection(connectionString))
{
sourceConnection.Open();
// Delete all from the destination table.
SqlCommand commandDelete = new SqlCommand();
commandDelete.Connection = sourceConnection;
commandDelete.CommandText =
"DELETE FROM dbo.BulkCopyDemoMatchingColumns";
commandDelete.ExecuteNonQuery();
// Add a single row that will result in duplicate key
// when all rows from source are bulk copied.
// Note that this technique will only be successful in
// illustrating the point if a row with ProductID = 446
// exists in the AdventureWorks Production.Products table.
// If you have made changes to the data in this table, change
// the SQL statement in the code to add a ProductID that
// does exist in your version of the Production.Products
// table. Choose any ProductID in the middle of the table
// (not first or last row) to best illustrate the result.
SqlCommand commandInsert = new SqlCommand();
commandInsert.Connection = sourceConnection;
commandInsert.CommandText =
"SET IDENTITY_INSERT dbo.BulkCopyDemoMatchingColumns ON;" +
"INSERT INTO " + "dbo.BulkCopyDemoMatchingColumns " +
"([ProductID], [Name] ,[ProductNumber]) " +
"VALUES(446, 'Lock Nut 23','LN-3416');" +
"SET IDENTITY_INSERT dbo.BulkCopyDemoMatchingColumns OFF";
commandInsert.ExecuteNonQuery();
// Perform an initial count on the destination table.
SqlCommand commandRowCount = new SqlCommand(
"SELECT COUNT(*) FROM dbo.BulkCopyDemoMatchingColumns;",
sourceConnection);
long countStart = System.Convert.ToInt32(
commandRowCount.ExecuteScalar());
Console.WriteLine("Starting row count = {0}", countStart);
// Get data from the source table as a SqlDataReader.
SqlCommand commandSourceData = new SqlCommand(
"SELECT ProductID, Name, ProductNumber " +
"FROM Production.Product;", sourceConnection);
SqlDataReader reader = commandSourceData.ExecuteReader();
// Set up the bulk copy object.
// Note that when specifying the UseInternalTransaction
// option, you cannot also specify an external transaction.
// Therefore, you must use the SqlBulkCopy construct that
// requires a string for the connection, rather than an
// existing SqlConnection object.
using (SqlBulkCopy bulkCopy = new SqlBulkCopy(
connectionString, SqlBulkCopyOptions.KeepIdentity |
SqlBulkCopyOptions.UseInternalTransaction))
{
bulkCopy.BatchSize = 10;
bulkCopy.DestinationTableName =
"dbo.BulkCopyDemoMatchingColumns";
// Write from the source to the destination.
// This should fail with a duplicate key error
// after some of the batches have been copied.
try
{
bulkCopy.WriteToServer(reader);
}
catch (Exception ex)
{
// Print the number of rows processed using the
// RowsCopied property.
Console.WriteLine("{0} rows were processed.",
bulkCopy.RowsCopied);
Console.WriteLine(ex.Message);
}
finally
{
reader.Close();
}
}
// Perform a final count on the destination
// table to see how many rows were added.
// Note that for this scenario, the value will
// not be equal to the RowsCopied property.
long countEnd = System.Convert.ToInt32(
commandRowCount.ExecuteScalar());
Console.WriteLine("Ending row count = {0}", countEnd);
Console.WriteLine("{0} rows were added.", countEnd - countStart);
Console.WriteLine("Press Enter to finish.");
Console.ReadLine();
}
}
private static string GetConnectionString()
// To avoid storing the sourceConnection string in your code,
// you can retrieve it from a configuration file.
{
return "Data Source=(local); " +
" Integrated Security=true;" +
"Initial Catalog=AdventureWorks;";
}
}
Använda befintliga transaktioner
Du kan ange ett befintligt SqlTransaction objekt som en parameter i en SqlBulkCopy konstruktor. I den här situationen utförs masskopieringsoperationen i den befintliga transaktionen och ingen ändring görs i transaktionstillståndet – den varken genomförs eller avbryts. Med den här metoden kan ett program inkludera masskopieringsåtgärden i en transaktion med andra databasåtgärder. Men om du inte anger ett SqlTransaction objekt och skickar en null-referens, och anslutningen har en aktiv transaktion, genereras ett undantag.
Om du behöver återställa hela masskopieringsåtgärden på grund av ett fel, eller om masskopian ska köras som en del av en större process som kan återställas, kan du ange ett SqlTransaction objekt till SqlBulkCopy konstruktorn.
Följande konsolprogram liknar det första exemplet (icke-transaktionellt), med ett undantag: i det här exemplet ingår masskopieringen i en större, extern transaktion. När primärnyckelöverträdelsefelet inträffar rullas hela transaktionen tillbaka och inga rader läggs till i måltabellen.
Viktigt!
Det här exemplet körs inte om du inte har skapat arbetstabellerna enligt beskrivningen i inställning av masskopieringsexempel. Den här koden tillhandahålls för att demonstrera syntaxen för att endast använda SqlBulkCopy. Om käll- och måltabellerna finns i samma SQL Server-instans är det enklare och snabbare att använda en Transact-SQL- INSERT ... SELECT-instruktion för att kopiera data.
using Microsoft.Data.SqlClient;
class Program
{
static void Main()
{
string connectionString = GetConnectionString();
// Open a sourceConnection to the AdventureWorks database.
using (SqlConnection sourceConnection =
new SqlConnection(connectionString))
{
sourceConnection.Open();
// Delete all from the destination table.
SqlCommand commandDelete = new SqlCommand();
commandDelete.Connection = sourceConnection;
commandDelete.CommandText =
"DELETE FROM dbo.BulkCopyDemoMatchingColumns";
commandDelete.ExecuteNonQuery();
// Add a single row that will result in duplicate key
// when all rows from source are bulk copied.
// Note that this technique will only be successful in
// illustrating the point if a row with ProductID = 446
// exists in the AdventureWorks Production.Products table.
// If you have made changes to the data in this table, change
// the SQL statement in the code to add a ProductID that
// does exist in your version of the Production.Products
// table. Choose any ProductID in the middle of the table
// (not first or last row) to best illustrate the result.
SqlCommand commandInsert = new SqlCommand();
commandInsert.Connection = sourceConnection;
commandInsert.CommandText =
"SET IDENTITY_INSERT dbo.BulkCopyDemoMatchingColumns ON;" +
"INSERT INTO " + "dbo.BulkCopyDemoMatchingColumns " +
"([ProductID], [Name] ,[ProductNumber]) " +
"VALUES(446, 'Lock Nut 23','LN-3416');" +
"SET IDENTITY_INSERT dbo.BulkCopyDemoMatchingColumns OFF";
commandInsert.ExecuteNonQuery();
// Perform an initial count on the destination table.
SqlCommand commandRowCount = new SqlCommand(
"SELECT COUNT(*) FROM dbo.BulkCopyDemoMatchingColumns;",
sourceConnection);
long countStart = System.Convert.ToInt32(
commandRowCount.ExecuteScalar());
Console.WriteLine("Starting row count = {0}", countStart);
// Get data from the source table as a SqlDataReader.
SqlCommand commandSourceData = new SqlCommand(
"SELECT ProductID, Name, ProductNumber " +
"FROM Production.Product;", sourceConnection);
SqlDataReader reader = commandSourceData.ExecuteReader();
//Set up the bulk copy object inside the transaction.
using (SqlConnection destinationConnection =
new SqlConnection(connectionString))
{
destinationConnection.Open();
using (SqlTransaction transaction =
destinationConnection.BeginTransaction())
{
using (SqlBulkCopy bulkCopy = new SqlBulkCopy(
destinationConnection, SqlBulkCopyOptions.KeepIdentity,
transaction))
{
bulkCopy.BatchSize = 10;
bulkCopy.DestinationTableName =
"dbo.BulkCopyDemoMatchingColumns";
// Write from the source to the destination.
// This should fail with a duplicate key error.
try
{
bulkCopy.WriteToServer(reader);
transaction.Commit();
}
catch (Exception ex)
{
// Print the number of rows processed using the
// RowsCopied property.
Console.WriteLine("{0} rows were processed.",
bulkCopy.RowsCopied);
Console.WriteLine(ex.Message);
transaction.Rollback();
}
finally
{
reader.Close();
}
}
}
}
// Perform a final count on the destination
// table to see how many rows were added.
long countEnd = System.Convert.ToInt32(
commandRowCount.ExecuteScalar());
Console.WriteLine("Ending row count = {0}", countEnd);
Console.WriteLine("{0} rows were added.", countEnd - countStart);
Console.WriteLine("Press Enter to finish.");
Console.ReadLine();
}
}
private static string GetConnectionString()
// To avoid storing the sourceConnection string in your code,
// you can retrieve it from a configuration file.
{
return "Data Source=(local); " +
" Integrated Security=true;" +
"Initial Catalog=AdventureWorks;";
}
}