86

I am getting the following error when I try to call a stored procedure that contains a SELECT Statement:

The operation is not valid for the state of the transaction

Here is the structure of my calls:

public void MyAddUpdateMethod()
{

    using (TransactionScope Scope = new TransactionScope(TransactionScopeOption.RequiresNew))
    {
        using(SQLServer Sql = new SQLServer(this.m_connstring))
        {
            //do my first add update statement

            //do my call to the select statement sp
            bool DoesRecordExist = this.SelectStatementCall(id)
        }
    }
}

public bool SelectStatementCall(System.Guid id)
{
    using(SQLServer Sql = new SQLServer(this.m_connstring)) //breaks on this line
    {
        //create parameters
        //
    }
}

Is the problem with me creating another connection to the same database within the transaction?

Avi Turner
  • 10,234
  • 7
  • 48
  • 75
Michael Kniskern
  • 24,792
  • 68
  • 164
  • 231

9 Answers9

70

After doing some research, it seems I cannot have two connections opened to the same database with the TransactionScope block. I needed to modify my code to look like this:

public void MyAddUpdateMethod()
{
    using (TransactionScope Scope = new TransactionScope(TransactionScopeOption.RequiresNew))
    {
        using(SQLServer Sql = new SQLServer(this.m_connstring))
        {
            //do my first add update statement            
        }

        //removed the method call from the first sql server using statement
        bool DoesRecordExist = this.SelectStatementCall(id)
    }
}

public bool SelectStatementCall(System.Guid id)
{
    using(SQLServer Sql = new SQLServer(this.m_connstring))
    {
        //create parameters
    }
}
Michael Kniskern
  • 24,792
  • 68
  • 164
  • 231
  • I stumbled onto same situation. I had to refer to two different databases within the same transaction scope. Thanks for the tip. – rageit Apr 09 '12 at 12:52
  • 5
    Good catch, a common place to see this happen is if you have a logging framework (nlog, log4net) that is writing to the DB, since the logging framework will create its own connection to the database as your application. – viggity Jul 11 '12 at 14:28
  • 2
    Logging applications *should* probably suppress any outer TransactionScope context. – user2864740 Jan 19 '17 at 07:35
  • NLog supresses any outer TransactionScope: https://github.com/NLog/NLog/wiki/Database-target – Alex Oct 17 '19 at 15:40
  • I opened same connection twice with using statements under same TransactionScope but still worked. I used SqlConnection instead of SQLServer as used in your example above. – Rajaram Shelar Dec 21 '20 at 12:25
18

When I encountered this exception, there was an InnerException "Transaction Timeout". Since this was during a debug session, when I halted my code for some time inside the TransactionScope, I chose to ignore this issue.

When this specific exception with a timeout appears in deployed code, I think that the following section in you .config file will help you out:

<system.transactions> 
        <machineSettings maxTimeout="00:05:00" /> 
</system.transactions>
R. Schreurs
  • 8,587
  • 5
  • 43
  • 62
14

I also come across same problem, I changed transaction timeout to 15 minutes and it works. I hope this helps.

TransactionOptions options = new TransactionOptions();
options.IsolationLevel = System.Transactions.IsolationLevel.ReadCommitted;
options.Timeout = new TimeSpan(0, 15, 0);
using (TransactionScope scope = new TransactionScope(TransactionScopeOption.Required,options))
{
    sp1();
    sp2();
    ...

}
Sharique
  • 4,199
  • 6
  • 36
  • 54
  • 18
    I strongly suspect that it's not the timeout that changed the behaviour but the fact that you've changed the isolation level from Serializable to ReadCommitted. – Russell Horwood May 27 '15 at 10:21
  • This exception can also occur in the case of timeout and the information about timeout should be also included in the exception data – Pawel Maga Apr 14 '21 at 21:05
8

For any wanderer that comes across this in the future. If your application and database are on different machines and you are getting the above error especially when using TransactionScope, enable Network DTC access. Steps to do this are:

  1. Add firewall rules to allow your machines to talk to each other.
  2. Ensure the distributed transaction coordinator service is running
  3. Enable network dtc access. Run dcomcnfg. Go to Component sevices > My Computer > Distributed Transaction Coordinator > Local DTC. Right click properties.
  4. Enable network dtc access as shown.

Important: Do not edit/change the user account and password in the DTC Logon account field, leave it as is, you will end up re-installing windows if you do.

DTC photo

J. Minjire
  • 1,003
  • 11
  • 22
5

I've encountered this error when my Transaction is nested within another. Is it possible that the stored procedure declares its own transaction or that the calling function declares one?

Wyatt
  • 1,366
  • 9
  • 14
  • I do not have any t-sql transaction code in any of my stored procedures. In theory, the transaction should be controlled by the MyAddUpdateMethod() – Michael Kniskern Oct 10 '08 at 22:04
  • +1 because I have received this error when the transaction language in my stored proc was wrong, i.e. transaction counts being messed up. – codeMonkey Mar 28 '17 at 16:48
3

For me, this error came up when I was trying to rollback a transaction block after encountering an exception, inside another transaction block.

All I had to do to fix it was to remove my inner transaction block.

Things can get quite messy when using nested transactions, best to avoid this and just restructure your code.

Vishav Premlall
  • 456
  • 6
  • 22
3

In my case, the solution was neither to increase the time of the "transactionscope" nor to increase the time of the "machineSettings" property of "system.transactions" of the machine.config file.

In this case there was something strange because this error only happened when the volume of information was very high.

So the problem was based on the fact that in the code inside the transaction there were many "foreach" that made updates for different tables (I had to solve this problem in a code developed by other personnel). If tests were performed with few records in the tables, the error was not displayed, but if the number of records was increased then the error was displayed.

In the end the solution was to change from a single transaction to several separate ones in the different "foreach" that were within the transaction.

Angel Angeles
  • 91
  • 1
  • 3
0

You can't have two transactions open at the same time. What I do is that I specify transaction.Complete() before returning results that will be used by the 2nd transaction ;)

Cătălin Rădoi
  • 1,804
  • 23
  • 43
0

I updated some proprietary 3rd party libraries that handled part of the database process, and got this error on all calls to save. I had to change a value in the web.config transaction key section because (it turned out) the referenced transaction scope method had moved from one library to another.

There was other errors previously connected with that key, but I got rid of them by commenting the key out (I know I should have been suspicious at that point, but I assumed it was now redundant as it wasn't in the shiny new library).

Louise
  • 382
  • 1
  • 6
  • 16