Search code examples
c#entity-frameworkentity-framework-6

EF6 Nested Transactions


I have a command service class, which utilises the unit of work pattern, with various methods to update a database (SQL Azure, in this case) via entity framework.

The command service gets instantiated with a reference to an instance of a dbcontext, whose lifetime is managed by my DI framework of choice.

Some of the command service class' methods wraps multiple updates to the database within a transaction, for example:

public void UpdateStuff(someEntity)
{
    using(var tx = _db.Database.BeginTransaction())
    {
        //Some updates to db
        _db.SaveChanges();
        //Some other updates to db
        _db.SaveChanges();
        tx.Commit();
    }
}

Now, some of these methods calls other methods of the command class from within their transactions, for instance:

public void UpdateWithSomeCascadingStuff(someOtherEntity)
{
    using(var tx = _db.Database.BeginTransaction())
    {
        //Some updates to db
        _db.SaveChanges();

        //Some other cascading logic and updates to db
        var relatedEntityToUpdate = _query.GetSomeEntityToUpdate(someOtherEntity);
        UpdateStuff(relatedEntityToUpdate);
        _db.SaveChanges();
        tx.Commit();
    }
}

Clearly, by doing this, I am nesting EF transactions for the same DbContext instance.

Is this supported and will it cause any trouble? Are there any alternative approaches I can take?

UPDATE: I am using EF6 Code First


Solution

  • EntityFramework's DBContexts implements both UnitOfWork and Repository patterns in itself.

    The context in EF6 also automatically wraps all commits in a transaction in itself (if it is not already part of one).

    So, no, you should not share a context between multiple units of work. They should each get their own.

    UPDATE

    If you try to start duplicate transactions on the same DbContext you get:

    An unhandled exception of type 'System.InvalidOperationException' occurred in EntityFramework.dll
    
    Additional information: The connection is already in a transaction and cannot participate in another transaction. EntityClient does not support parallel transactions.
    

    So no, you can't do what you are asking for.