Two nested Entity Framework contexts, sharing a transaction

c# entity-framework-6 sql-server transactions

Question

I have code that looks like the example below. There's an explicit transaction involved because of some database tomfoolery that needs to be done via a SP, and a save changes in the middle of it all. (Exception handling, rollbacks, etc.. omitted):

void OuterMethod(MyDatbase context)
{
    using(var dbTrans = context.Database.BeginTransaction())
    {
        // some stuff, the save puts the data where the SP can see it
        Stuff(context);
        context.SaveChanges();

        // now some SP stuff
        context.Database.ExecuteSqlCommand(@"spFoo", params);

        // more stuff
        MoreStuff(context);
        AlmostUnrelatedCode(context);
        context.SaveChanges();

        dbTrans.Commit();
    }
}

Right now the method AlmostUnrelatedCode() -- which is only marginally related to the process above -- needs a nice, fast, disposable read-only context 99% of the time. I have a factory that will serve me up the right kind of context when I need it. The 1% of the time it's called from the middle of that block above.

MyDatabase localReadOnlyContext;

void AlmostUnrelatedCode(MyDatabase context)
{
    if ( context.Database.CurrentTransaction != null )
    {
        // Must use the context passed or everything deadlocks  :(
        localReadOnlyContext = context;
        disposeContextLater = false;
    }
    else
    {
        // I just want to do this all the time
        localReadOnlyContext = _contextFactory.CreateReadOptimized();
        disposeContextLater = true;
    }

    // Do many, many things with my read-optimized context...

    // The Dispose() on the class will check for disposeContextLater
}

What I'd like to do is to get rid of that transaction check, and in fact not need to pass the outer context at all if I can help it.

What I've tried:

  • Just ignoring what's going on in the outer transaction and using the context I generate all the time. Problem: deadlocks.

  • Trying to get the outermost transaction into the EF context I create with the _contextFactory. Problem: EF context constructors don't allow you to pass an existing transaction; also Database.CurrentTransaction has no setter.

  • Pulling the whole transaction out into a TransactionScope that wraps everything up. Problem: the method OuterMethod passes in the context, and I don't have control of the caller.

What I can't try:

  • Dirty reads/nolock. AlmostUnrelatedCode() needs the data as written so far.

I'd rather not:

  • Just keep using the outer context while inside of AlmostUnrelatedCode. AlmostUnrelatedCode deals with a lot of data trees and that context gets fat and unhappy really fast. It pollutes its context with crap really fast, and I'd rather just dispose of it when I'm done.
1
0
8/13/2018 9:09:54 PM

Popular Answer

Can't you separate things done in AlmostUnrelatedCode like this:

void AlmostUnrelatedCode()
{
   var context = _contextFactory.CreateReadOptimized();
   AlmostUnrelatedCode(context);
   context.Dispose();
}

void AlmostUnrelatedCode(MyDatabase context)
{
    // Do many, many things with context...
}

Now you can call AlmostUnrelatedCode(with param) from your OuterMethod. And maybe there is even more to be separated. Consider SOLID.

1
8/14/2018 6:40:44 AM


Related Questions





Related

Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow
Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow