2014-10-27 17 views
12

sto inserendo i dati tramite SqlBulkCopy in questo modo:SqlBulkCopy avvia automaticamente una transazione?

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); 
     } 
    } 
} 

sarà questo automaticamente avvolgere in una transazione di SQL in modo che se qualcosa va storto a metà strada attraverso il DB sarà lasciato nello stesso stato in cui era prima della è iniziato l'inserimento di massa? O sarà inserita la metà dei dati?

vale a dire è necessario per me di chiamare esplicitamente con.BeginTransaction

O se io chiamo costruttore SqlBulkCopy s' che prende una stringa, è che un modo migliore di ottenerlo si verifichi in una transazione?

public void testBulkInsert(string connection, string table, DataTable dt) 
{ 
    using (SqlBulkCopy bulkCopy = new SqlBulkCopy(connection)) 
    { 
     bulkCopy.DestinationTableName = table; 
     bulkCopy.WriteToServer(dt); 
    } 
} 

trovo il docs un po 'poco chiaro in questa materia come affermano inizialmente che

Per impostazione predefinita, un'operazione di copia di massa viene eseguita come un un'operazione isolata. L'operazione di copia di massa avviene in modo non transazionale, senza possibilità per il rotolamento indietro

ma poi stato

Per impostazione predefinita, un'operazione di copia di massa è la sua propria transazione. Quando si si desidera eseguire un'operazione di copia bulk dedicata, creare una nuova istanza di SqlBulkCopy con una stringa di connessione o utilizzare un oggetto SqlConnection esistente senza una transazione attiva. In ogni scenario, crea l'operazione di copia bulk e quindi esegue il commit o il rollback della transazione .

Quindi è necessario fare:

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(); 
     } 
    } 
} 
+0

Perché non provi? E quale parte della documentazione ti ha fatto pensare che lo avrebbe fatto? – TomTom

+1

Questa parte: * Per impostazione predefinita, un'operazione di copia di massa è una sua transazione *, ma poi dice anche * L'operazione di copia di massa avviene in modo non transato, senza alcuna possibilità di ripristinarlo * così ... è una specie di confusione – Dan

+0

Controllare la modifica. – mybirthname

risposta

25

No qui è il testo da SqlBulkCopy documentazione msdn

Per impostazione predefinita, un'operazione di copia di massa viene eseguita come un un'operazione isolata. L'operazione di copia di massa si verifica in modo non transazionale, senza alcuna possibilità di rollback. Se è necessario eseguire il rollback di tutto lo o parte della copia bulk quando si verifica un errore, è possibile utilizzare una transazione gestita da SqlBulkCopy, eseguire l'operazione di copia bulk all'interno di una transazione esistente o essere inserita in un System.Transactions Transazione.

EDIT: leggere correttamente la documentazione, dal link che ti ho dato:

Per impostazione predefinita, un'operazione di copia di massa è la sua propria transazione. Quando si si desidera eseguire un'operazione di copia bulk dedicata, creare una nuova istanza di SqlBulkCopy con una stringa di connessione oppure utilizzare un oggetto SqlConnection esistente senza una transazione attiva.In ogni scenario , l'operazione di copia bulk crea, quindi esegue il commit o esegue il rollback della transazione su .

Questo è scritto per l'operazione di copia di massa interna caso, che non è il default!

using (SqlBulkCopy bulkCopy = new SqlBulkCopy(
         connectionString, SqlBulkCopyOptions.KeepIdentity | 
         SqlBulkCopyOptions.UseInternalTransaction)) 
    { 
     .... 
    } 

Guardare da vicino in SqlBulkCopyOptions.UseInternalTransaction! Si specifica esplicitamente l'opzione UseInternalTransaction nel costruttore della classe SqlBulkCopy per causare esplicitamente un'operazione di copia di massa da eseguire nella propria transazione, causando l'esecuzione di ogni batch dell'operazione di copia di massa in una transazione separata. I diversi batch vengono eseguiti in transazioni diverse , se si verifica un errore durante l'operazione di copia bulk, tutte le righe del batch corrente verranno sottoposte a rollback, ma le righe dei batch precedenti rimarranno nel database.


Se è necessario ripristinare l'intera operazione di copia di massa perché si verifica un errore, o se la copia di massa deve eseguire come parte di un processo più ampio che può essere arrotolato indietro, si può fornire un oggetto SqlTransaction al costruttore SqlBulkCopy.

Il caso di transazione esterna.

  using (SqlTransaction transaction = 
         destinationConnection.BeginTransaction()) 
      { 
       using (SqlBulkCopy bulkCopy = new SqlBulkCopy(
          destinationConnection, SqlBulkCopyOptions.KeepIdentity, 
          transaction)) 
       { 
        .... 
       } 
      } 

come ho detto in accattonaggio la risposta è no, si dovrebbe utilizzare la transazione esistente o operazione di copia di massa interna. Leggi il file di documentazione che si trova nel link, per maggiori informazioni.

Se si desidera avere una transazione, è necessario utilizzare uno dei due casi che ho scritto.

+0

Dice in quei documenti: * Per impostazione predefinita, un'operazione di copia bulk è una sua transazione. Quando si desidera eseguire un'operazione di copia bulk dedicata, creare una nuova istanza di SqlBulkCopy con una stringa di connessione o utilizzare un oggetto SqlConnection esistente senza una transazione attiva. In ogni scenario, l'operazione di copia bulk crea, quindi esegue il commit o il rollback della transazione. * Questo significa che se utilizzo 'sqlBulkCopy bulkCopy = new SqlBulkCopy (connection)) invece di quello che ho, allora sarà in una transazione? O è meglio chiamare me stesso con con.BeginTransaction? – Dan

+0

@Dan controlla la modifica e dimmi se qualcosa non è chiaro! – mybirthname

+1

Grazie, è chiaro. – Dan

Problemi correlati