简体   繁体   中英

How to use transactions for different contexts?

In my application I have method looks like this:

public static bool DoLargeOperation()
{
    bool res = true;

    res = res && DoFirstSubOperation();
    res = res && DoSecondSubOperation();
    res = res && DoThirdSubOperation();

    return res;
}

And each of the internal methods looks like this:

public static bool DoFirstSubOperation()
{
    using (var context = new EntityFrameworkContext())
    {
        // data modification.
        context.SaveChanges();
    }
}

For example, DoFirstSubOperation() and DoSecondSubOperation() complete successfully, but DoThirdSubOperation() fails. How do I rollback the changes made by the first two functions?

This approach has not brought results:

using (var transaction = new TransactionScope())
{
    res = res && DoFirstSubOperation();
    res = res && DoSecondSubOperation();
    res = res && DoThirdSubOperation();
}

The only solution I see is to define the context like so:

public static bool DoLargeOperation()
{
    bool res = true;

    using (var context = new EntityFrameworkContext())
    {
        using (var transaction = context.Database.BeginTransaction())
        {

            res = res && DoFirstSubOperation(context);
            res = res && DoSecondSubOperation(context);
            res = res && DoThirdSubOperation(context);
            if (res)
            {
                transaction.Commit();
            }
            else
            {
                transaction.Rollback();
            }
        }
    }

    return res;
}

But is it acceptable to do so? Or is there another solution?

Yes, that is the correct pattern. Passing the context into the methods allows the methods to be reused in multiple locations because the context and transaction will be managed by the caller.

Although, you will probably want to stop processing subsequent methods once the first one fails. You also probably want to wrap the call to the children in a try/catch so that any exception allows the rollback to occur correctly...

try
{
    res = DoFirstSubOperation(context);
    if (res) 
        res = DoSecondSubOperation(context);
    if (res) 
        res = DoThirdSubOperation(context);    

    if (res)
        transaction.Commit();
    else
        transaction.Rollback();
}
catch
{
    transaction.Rollback();
}

If your child methods already handle exceptions then you can forgo the try/catch.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM