Two nested Entity Framework contexts, sharing a transaction

c# entity-framework-6 sql-server transactions

Question

I have code that resembles the illustration below. Due to some database tinkering that requires the use of an SP, there is an explicit transaction involved, and in the midst of everything there is a save changes command. (Exceptions for rollbacks, exception handling, etc.):

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

Currently, the techniqueAlmostUnrelatedCode() which is 99% of the time unrelated to the procedure above—needs a beautiful, quick, throwaway read-only environment. When I need it, I have a factory that will provide me with the appropriate context. In 1% of cases, the call comes from the centre of the 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
}

With What I want to do, the transaction check will be eliminated, and if I can avoid it, I won't even need to provide the outside context.

Attempts I've made:

  • Using the context I create on a regular basis and disregarding what is happening in the outside transaction. The issue is deadlocks.

  • attempting to include the most recent transaction in the EF context I establish using the_contextFactory . Problem: EF context constructors don't allow you to pass an existing transaction; alsoDatabase.CurrentTransaction without a setter.

  • converting the whole transaction into aTransactionScope That completes the sentence. Issue: the approachOuterMethod I don't have control over the caller, and it sends the context to in.

What I cannot attempt

  • Nolock/dirty reads.AlmostUnrelatedCode() need the information as it has been previously written.

I prefer not to:

  • Simply continue to use the external context inside ofAlmostUnrelatedCode . AlmostUnrelatedCode works with several data trees, and that context quickly becomes bloated and dissatisfied. I'd like to simply throw it away when I'm through since it quickly contaminates its setting with trash.
1
0
8/13/2018 9:09:54 PM

Popular Answer

Can't you divide what has been done intoAlmostUnrelatedCode as in this:

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

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

You may now dial.AlmostUnrelatedCode(with param) as per yourOuterMethod . Perhaps there is still more that needs to be separated. Think about 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