web-dev-qa-db-fra.com

Quand "SqlConnection ne prend pas en charge les transactions parallèles" se produit-il?

J'ai une tonne de code plutôt fonctionnel qui est là depuis des mois et aujourd'hui, j'ai vu l'exception suivante enregistrée:

System.InvalidOperationException
SqlConnection does not support parallel transactions.
    at System.Data.SqlClient.SqlInternalConnection.BeginSqlTransaction(
       IsolationLevel iso, String transactionName)
    at System.Data.SqlClient.SqlConnection.BeginTransaction(
       IsolationLevel iso, String transactionName)
    at my code here

et j'aimerais savoir pourquoi cette exception a été levée. J'ai lu la description MSDN de BeginTransaction() et tout ce qu'il dit, c'est que, parfois, cette exception peut être levée.

Que signifie exactement cette exception? Quelle est la lacune de mon code que je devrais rechercher?

25
sharptooth

Vous obtiendrez ceci si la connexion a déjà une transaction non validée et vous appelez à nouveau BeginTransaction.

Dans cet exemple:

class Program
{
    static void Main(string[] args)
    {
        using (SqlConnection conn = new SqlConnection("Server=.;Database=TestDb;Trusted_Connection=True;"))
        {
            conn.Open();

            using (var tran = conn.BeginTransaction())
            {
                using (var cmd = new SqlCommand("INSERT INTO TESTTABLE (test) values ('" + DateTime.Now.ToString() + "')", conn))
                {
                    cmd.Transaction = tran;
                    cmd.ExecuteNonQuery();
                }

                using (var tran2 = conn.BeginTransaction())    // <-- EXCEPTION HERE
                {
                    using (var cmd = new SqlCommand("INSERT INTO TESTTABLE (test) values ('INSIDE" + DateTime.Now.ToString() + "')", conn))
                    {
                        cmd.Transaction = tran2;
                        cmd.ExecuteNonQuery();
                    }

                    tran2.Commit();
                }

                tran.Commit();
            }
        }
    }
}

... J'obtiens exactement la même exception lors de la deuxième BeginTransaction.

Assurez-vous que la première transaction est validée ou annulée avant la suivante.

Si vous voulez des transactions imbriquées, vous trouverez peut-être TransactionScope est la voie à suivre.

19
SimonGoldstone

Le même problème se produit lorsque vous utilisez la "mauvaise" méthode pour une transaction, cela s'est produit après la mise à niveau vers une version plus récente d'Entity Framework.

Dans le passé, nous utilisions la méthode suivante pour créer une transaction et des requêtes linq fortement typées EF avec des requêtes SQL, mais comme la propriété Connection n'existait plus, nous avons remplacé toutes les db. avec db.Database, ce qui était faux:

// previous code
db.Connection.Open();
using (var transaction = db.Connection.BeginTransaction())
{
    // do stuff inside transaction
}
// changed to the following WRONG code
db.Database.Connection.Open();
using (var transaction = db.Database.Connection.BeginTransaction())
{
    // do stuff inside transaction
}

Quelque part, ils ont changé le comportement de ce comportement de méthode de transaction avec une version plus récente d'Entity Framework et la solution consiste à utiliser:

db.Database.Connection.Open();
using (var transaction = db.Database.BeginTransaction())
{
    // do stuff inside transaction
}

Notez que la transaction est maintenant appelée sur Database au lieu de Connection.

11
Silvermind