SqlBulkCopy avvia automaticamente una transazione?

bulkinsert c# sqlbulkcopy sql-server transactions

Domanda

Sto inserendo i dati tramite SqlBulkCopy modo:

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

Questo verrà automaticamente racchiuso in una transazione SQL in modo che se qualcosa va male a metà del DB rimarrà nello stato in cui era prima che iniziasse l'inserimento di massa? O sarà inserita la metà dei dati?

cioè è necessario che io chiami esplicitamente con.BeginTransaction

O se chiamo il costruttore di SqlBulkCopy che prende una stringa, è un modo migliore per farlo accadere 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 i documenti un po 'oscuri su questo argomento, come inizialmente affermano che

Per impostazione predefinita, un'operazione di copia bulk viene eseguita come un'operazione isolata. L'operazione di copia di massa avviene in modo non transato, senza possibilità di ripristinarlo

ma poi lo stato successivo

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

Risposta accettata

No here is text dalla documentazione di SqlBulkCopy in msdn

Per impostazione predefinita, un'operazione di copia bulk viene eseguita come un'operazione isolata. L'operazione di copia di massa avviene in modo non transato, senza possibilità di ripristinarlo. Se è necessario eseguire il rollback di tutto 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 una transazione System.Transactions.

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

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 e quindi esegue il commit o il rollback della transazione.

Questo è scritto per la transazione di copia bulk interna del caso, che non è l'impostazione predefinita!

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

Guarda da vicino SqlBulkCopyOptions.UseInternalTransaction ! Si specifica esplicitamente l'opzione UseInternalTransaction nel costruttore della classe SqlBulkCopy per provocare 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 eseguire il rollback dell'intera operazione di copia bulk perché si verifica un errore o se la copia bulk deve essere eseguita come parte di un processo più ampio che può essere ripristinato, è possibile 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 all'inizio, la risposta è no, dovresti usare la transazione esistente o la transazione interna di copia bulk. Leggi il file di documentazione che si trova nel link, per maggiori informazioni.

Se vuoi avere una transazione dovresti usare uno dei due casi che ho scritto.



Autorizzato sotto: CC-BY-SA with attribution
Non affiliato con Stack Overflow
Autorizzato sotto: CC-BY-SA with attribution
Non affiliato con Stack Overflow