SqlBulkCopy lance-t-il automatiquement une transaction?

bulkinsert c# sqlbulkcopy sql-server transactions

Question

SqlBulkCopy données via SqlBulkCopy comme ceci:

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

Cela sera-t-il automatiquement encapsulé dans une transaction SQL afin qu'en cas de problème, la moitié de la base de données reste dans le même état qu'avant le début de l'insertion en bloc? Ou la moitié des données seront-elles insérées?

c'est-à-dire qu'il m'est nécessaire d'appeler explicitement con.BeginTransaction

Ou si j'appelle le constructeur de SqlBulkCopy qui prend une chaîne, est-ce une meilleure façon de l'obtenir dans une transaction?

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

Je trouve que les docs sont un peu flous à ce sujet car ils déclarent initialement que

Par défaut, une opération de copie en bloc est effectuée en tant qu'opération isolée. L’opération de copie en bloc s’effectue de manière non traitée, sans possibilité de restauration.

mais ensuite, plus tard

Par défaut, une opération de copie en bloc est sa propre transaction. Lorsque vous souhaitez effectuer une opération de copie en bloc dédiée, créez une nouvelle instance de SqlBulkCopy avec une chaîne de connexion ou utilisez un objet SqlConnection existant sans transaction active. Dans chaque scénario, l'opération de copie en bloc crée, puis valide ou annule la transaction.

Alors faut-il faire:

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

Réponse acceptée

Non ici est un texte de SqlBulkCopy documentation msdn

Par défaut, une opération de copie en bloc est effectuée en tant qu'opération isolée. L'opération de copie en bloc se produit sans transaction, sans possibilité de l'annuler. Si vous devez annuler tout ou partie de la copie en bloc lorsqu'une erreur se produit, vous pouvez utiliser une transaction gérée par SqlBulkCopy , effectuer l'opération de copie en bloc dans une transaction existante ou être inscrit dans une transaction System.Transactions.

EDIT: Lisez correctement la documentation, à partir du lien que je vous ai donné:

Par défaut, une opération de copie en bloc est sa propre transaction. Lorsque vous souhaitez effectuer une opération de copie en bloc dédiée, créez une nouvelle instance de SqlBulkCopy avec une chaîne de connexion ou utilisez un
objet SqlConnection existant sans transaction active. Dans chaque scénario, l'opération de copie en bloc crée, puis valide ou annule la transaction.

Ceci est écrit pour la transaction de copie en bloc interne au cas, ce qui n'est pas la valeur par défaut!

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

Examinez attentivement SqlBulkCopyOptions.UseInternalTransaction ! Vous spécifiez explicitement l'option UseInternalTransaction dans le constructeur de la classe SqlBulkCopy afin de provoquer explicitement l'exécution d'une opération de copie en bloc dans sa propre transaction, ce qui entraîne l'exécution de chaque lot de l'opération de copie en bloc dans une transaction distincte. Si une erreur se produit pendant l'opération de copie en bloc, toutes les lignes du lot actuel seront annulées, mais les lignes des lots précédents resteront dans la base de données.


Si vous devez annuler la totalité de l'opération de copie en bloc en raison d'une erreur ou si la copie en bloc doit être exécutée dans le cadre d'un processus plus volumineux, vous pouvez fournir un objet SqlTransaction au constructeur SqlBulkCopy.

Le cas de transaction externe.

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

Comme je l'ai dit au début, la réponse est non, vous devez utiliser une transaction existante ou une transaction de copie en bloc interne. Lisez le fichier de documentation qui se trouve dans le lien pour plus d'informations.

Si vous voulez avoir une transaction, vous devriez utiliser l'un des deux cas que j'ai écrits.



Sous licence: CC-BY-SA with attribution
Non affilié à Stack Overflow
Est-ce KB légal? Oui, apprenez pourquoi
Sous licence: CC-BY-SA with attribution
Non affilié à Stack Overflow
Est-ce KB légal? Oui, apprenez pourquoi