質問

UPDATE based on accepted answer:

bool success = false;
using (var bulkCopy = new SqlBulkCopy(connection)) //using!
{
    connection.Open();

    //explicit isolation level is best-practice
    using (var tran = connection.BeginTransaction(IsolationLevel.ReadCommitted))
    {
        bulkCopy.DestinationTableName = "table";
        bulkCopy.ColumnMappings...

        using (var dataReader = new ObjectDataReader<SomeObject>(paths))
        {            
            bulkCopy.WriteToServer(dataReader);
            success = true;
        }

        tran.Commit(); //commit, will not be called if exception escapes
    }
}
return success;

I use BulkCopy class for large insert and it works fine.
After execute WriteToServer and saving data to database
I wan't to know are all data saved successfully so I can return true/false because I need to save all or nothing?

    var bulkCopy = new SqlBulkCopy(connection);

    bulkCopy.DestinationTableName = "table";

    bulkCopy.ColumnMappings...

    using (var dataReader = new ObjectDataReader<SomeObject>(paths))
    {
        try
        {
        bulkCopy.WriteToServer(dataReader);
        }
        catch(Exception ex){ ... }    
}
役に立ちましたか?

解決

If the call to WriteToServer completed without exceptions, all rows were saved and are on disk. This is just the standard semantics for SQL Server DML. Nothing special with bulk copy.

Like all other DML, SqlBulkCopy is all-or-nothing as well. Except if you configure a batch size which you did not.

using (var bulkCopy = new SqlBulkCopy(connection)) //using!
{
    connection.Open();

    //explicit isolation level is best-practice
    using (var tran = connection.BeginTransaction(IsolationLevel.ReadCommitted))
    {
        bulkCopy.DestinationTableName = "table";
        bulkCopy.ColumnMappings...

        using (var dataReader = new ObjectDataReader<SomeObject>(paths))
        {
            //try
            //{
            bulkCopy.WriteToServer(dataReader, /*here you set some options*/);
            //}
            //catch(Exception ex){ ... } //you need no explicit try-catch here
        }

        tran.Commit(); //commit, will not be called if exception escapes
    }
}

I've added you sample code that I aligned with best-practices.

他のヒント

There is no direct way of identifying if the process was completed successfully or not, other than to look for/catch any exceptions raised by WriteToServer() method.

An alternative approach might be to check the number of records in the database, and then check the number of records after the process completes - The difference being the number that were inserted. Comparing this value against the numbers of records to be inserted could give an idea of failure or success. However, this is not fool proof particularly if there are other process inserting/deleting records.

However, these techniques in conjunction with TransactionScope - http://msdn.microsoft.com/en-us/library/system.transactions.transactionscope.aspx - or something similar should achieve what you require.

EDIT

By Default each insert operation is processed as a batch; if the operation fails in a particular batch then that batch is rolled back, not any inserted before it.

However, If an internal transaction is applied to the bulk operation than a failure in any row can roll back the entire result set. For Example;

using (SqlBulkCopy bulkCopy =
   new SqlBulkCopy(connectionString, SqlBulkCopyOptions.KeepIdentity
                   | SqlBulkCopyOptions.UseInternalTransaction))
{
   bulkCopy.BatchSize = 10;
   bulkCopy.DestinationTableName = "dbo.BulkCopyDemoMatchingColumns";

   try
   {
      bulkCopy.WriteToServer(reader);
   }
   catch (Exception ex)
   {
      Console.WriteLine(ex.Message);
   }
   finally
   {
      bulkCopy.Close();
   }
}

An error in any of the above operation would cause the entire operation to roll back. See more details on this at http://msdn.microsoft.com/en-us/library/tchktcdk.aspx.

From the docs for this function, the following snippet suggests that you should catch any exceptions that are thrown and otherwise you can take it that the operation was successful.

using (SqlBulkCopy bulkCopy = new SqlBulkCopy(connectionString))
{
     bulkCopy.DestinationTableName = "dbo.BulkCopyDemoMatchingColumns";
     try
     {
         // Write from the source to the destination.
         bulkCopy.WriteToServer(reader);
     }
     catch (Exception ex)
     {
         Console.WriteLine(ex.Message);
     }
     finally
     {
         // Close the SqlDataReader. The SqlBulkCopy 
         // object is automatically closed at the end 
         // of the using block.
         reader.Close();
     }
}

If you want to be super-sure, execute a query against the database to check the rows are there, after the bulk copy completes.

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top