Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

When does "SqlConnection does not support parallel transactions" happen?

I have a ton of rather working code that's been here for months and today I saw the following exception logged:

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

and I'd like to investigate why this exception was thrown. I've read MSDN description of BeginTransaction() and all it says is that well, sometimes this exception can be thrown.

What does this exception mean exactly? What is the deficiency in my code that I should be looking for?

like image 478
sharptooth Avatar asked Oct 24 '13 07:10

sharptooth


People also ask

When should you use the SqlConnection object?

If you want to access a database multiple times, you should establish a connection using the Connection object. You can also make a connection to a database by passing a connection string via a Command or Recordset object. However, this type of connection is only good for one specific, single query.

Do I need to call SqlConnection open?

The SqlConnection draws an open connection from the connection pool if one is available. Otherwise, it establishes a new connection to an instance of SQL Server. If the SqlConnection goes out of scope, it is not closed. Therefore, you must explicitly close the connection by calling Close.

What is SqlConnection and SqlCommand in C#?

SqlConnection and SqlCommand are classes of a connected architecture and found in the System. Data. SqlClient namespace. The SqlConnection class makes a connection with the database. Further, this connection (database connection) is used by the SqlCommand to work with that database.


2 Answers

You'll get this if the connection already has an uncommitted transaction and you call BeginTransaction again.

In this example:

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

... I get exactly the same exception at the second BeginTransaction.

Make sure the first transaction is committed or rolled back before the next one.

If you want nested transactions, you might find TransactionScope is the way forward.

like image 93
SimonGoldstone Avatar answered Oct 21 '22 20:10

SimonGoldstone


The same problem occurs when using the 'wrong' method for a transaction, this happened after we upgraded to a newer version of the Entity Framework.

In the past we were using the following method to create a transaction and mixed EF strong typed linq queries with Sql queries, but since the Connection property did not exist anymore, we replaced all db. with db.Database, which was wrong:

// 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
}

Somewhere they changed the behaviour of that transaction method behaviour with a newer version of the Entity Framework and the solution is to use:

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

Notice that the transaction is now callen on Database instead of Connection.

like image 21
Silvermind Avatar answered Oct 21 '22 21:10

Silvermind