如何在不同的上下文环境中使用事务?

5
在我的应用中,我有一个方法看起来像这样:

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

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

    return res;
}

每个内部方法都是这样的:

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

例如,DoFirstSubOperation()DoSecondSubOperation()成功完成,但DoThirdSubOperation()失败了。我该如何回滚前两个函数所做的更改?
这种方法没有带来结果:
using (var transaction = new TransactionScope())
{
    res = res && DoFirstSubOperation();
    res = res && DoSecondSubOperation();
    res = res && DoThirdSubOperation();
}

我认为唯一的解决方案是这样定义上下文:

上下文就是一个可以描述数据环境的概念。

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

但这样做可行吗?或者还有其他解决方案吗?

这种方法有什么问题吗?这是实现你所需的功能最正确的方式。 - abatishchev
它不会回滚已完成操作中的更改。 - Egor Lavrentev
没有 scope.Commit(),它就不会提交它们。你如何检查更改?也许你在同一个事务中?或者是外部的,比如使用 Management Studio? - abatishchev
是的,我的更改已保存在数据库中,而没有使用scope.Commit()。当DoLargeOperation()失败时,我使用MySQL Workbench检查更改。 - Egor Lavrentev
哦,我明白了。MySQL。我有点惊讶TransactionScope居然可以和它一起使用,看看这个链接:https://dev59.com/U2oy5IYBdhLWcg3wF6QL - abatishchev
1个回答

5

是的,这是正确的模式。将上下文传递到方法中允许在多个位置重复使用方法,因为调用方会管理上下文和事务。

不过,一旦第一个方法失败,您可能希望停止处理后续方法。您还可能希望在调用子级时包装try/catch,以便任何异常都可以正确地执行回滚...

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

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

如果您的子方法已经处理了异常,那么您可以放弃使用try/catch。

谢谢!我只是简化了示例,以展示其本质。 - Egor Lavrentev

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接