I am inserting data via SqlBulkCopy
like so:
public void testBulkInsert(string connection, string table, DataTable dt) { using (SqlConnection con = new SqlConnection(connection)) { con.Open(); using (SqlBulkCopy bulkCopy = new SqlBulkCopy(con)) { bulkCopy.DestinationTableName = table; bulkCopy.WriteToServer(dt); } } }
Will this automatically be wrapped in a SQL transaction so that if something goes wrong half way through the DB will be left in the same state as it was before the bulk insert began? Or will half the data be inserted?
i.e. is it necessary for me to explicitly call con.BeginTransaction
Or if I call SqlBulkCopy
's constructor that takes a string, is that a better way of getting it to occur in a transaction?
public void testBulkInsert(string connection, string table, DataTable dt) { using (SqlBulkCopy bulkCopy = new SqlBulkCopy(connection)) { bulkCopy.DestinationTableName = table; bulkCopy.WriteToServer(dt); } }
I find the docs a bit unclear on this matter as they initially state that
By default, a bulk copy operation is performed as an isolated operation. The bulk copy operation occurs in a non-transacted way, with no opportunity for rolling it back
but then later state
By default, a bulk copy operation is its own transaction. When you want to perform a dedicated bulk copy operation, create a new instance of SqlBulkCopy with a connection string, or use an existing SqlConnection object without an active transaction. In each scenario, the bulk copy operation creates, and then commits or rolls back the transaction.
So is it necessary to do:
public void testBulkInsert(string connection, string table, DataTable dt) { using (SqlConnection con = new SqlConnection(connection)) { con.Open(); using (SqlTransaction tr = con.BeginTransaction(IsolationLevel.Serializable)) { using (SqlBulkCopy bulkCopy = new SqlBulkCopy(con, SqlBulkCopyOptions.Default, tr)) { bulkCopy.DestinationTableName = table; bulkCopy.WriteToServer(dt); } tr.Commit(); } } }
The SqlBulkCopy class can be used to write data only to SQL Server tables. However, the data source is not limited to SQL Server; any data source can be used, as long as the data can be loaded to a DataTable instance or read with a IDataReader instance.
Upload the data to the temporary table, then perform the SqlBulkCopy update. Using SqlBulkCopy(), upload the datatable's data to the temporary table. Then execute a SQL command to update the main table's data from the temporary table. Finally drop the temporary table.
BatchSize = 4000; By default, SqlBulkCopy will process the operation in a single batch. If you have 100000 rows to copy, 100000 rows will be copied at once. Not specifying a BatchSize can impact your application: Decrease SqlBulkCopy performance.
The SQL Server bulk copy feature supports the transfer of large amounts of data into or out of a SQL Server table or view. Data can also be transferred out by specifying a SELECT statement. The data can be moved between SQL Server and an operating-system data file, such as an ASCII file.
No here is text from SqlBulkCopy
documentation in msdn
By default, a bulk copy operation is performed as an isolated operation. The bulk copy operation occurs in a non-transacted way, with no opportunity for rolling it back. If you need to roll back all or part of the bulk copy when an error occurs, you can use a SqlBulkCopy-managed transaction, perform the bulk copy operation within an existing transaction, or be enlisted in a System.Transactions Transaction.
EDIT: Read properly the documentation, from the link which I gave you:
By default, a bulk copy operation is its own transaction. When you want to perform a dedicated bulk copy operation, create a new instance of SqlBulkCopy with a connection string, or use an
existing SqlConnection object without an active transaction. In each scenario, the bulk copy operation creates, and then commits or rolls back the transaction.
This is written for the case internal bulk copy transaction, which is not the default!
using (SqlBulkCopy bulkCopy = new SqlBulkCopy( connectionString, SqlBulkCopyOptions.KeepIdentity | SqlBulkCopyOptions.UseInternalTransaction)) { .... }
Look closely in SqlBulkCopyOptions.UseInternalTransaction
! You are explicitly specify the UseInternalTransaction option in the SqlBulkCopy class constructor to explicitly cause a bulk copy operation to execute in its own transaction, causing each batch of the bulk copy operation to execute within a separate transaction.Since different batches are executed in different transactions, if an error occurs during the bulk copy operation, all the rows in the current batch will be rolled back, but rows from previous batches will remain in the database.
If you need to roll back the entire bulk copy operation because an error occurs, or if the bulk copy should execute as part of a larger process that can be rolled back, you can provide a SqlTransaction object to the SqlBulkCopy constructor.
The external transaction case.
using (SqlTransaction transaction = destinationConnection.BeginTransaction()) { using (SqlBulkCopy bulkCopy = new SqlBulkCopy( destinationConnection, SqlBulkCopyOptions.KeepIdentity, transaction)) { .... } }
Like I said in the begging the answer is no, you should use existing transaction or internal bulk copy transaction. Read the documentation file which is in the link, for more information.
If you want to have transaction you should use one of the two cases which I wrote.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With