多个方法调用的函数委托

本文关键字:函数 调用 方法 | 更新日期: 2023-09-27 18:24:50

我之前问过使用SqlConnection转换为Func委托

如何使用以下委托使用同一事务进行多个调用?更复杂的是,其中一个调用我希望返回一个值。

我有以下代理功能定义

protected TResult UsingSqlTransaction<TResult>(Func<SqlTransaction, TResult> myFunction)
{
    using (SqlConnection sqlConn = new SqlConnection(ConnectionString))
    {
        sqlConn.Open();
        using (SqlTransaction sqlTrans = sqlConn.BeginTransaction())
        {
            var result = myFunction(sqlTrans);
            sqlTrans.Commit();
            return result;
        }
    }
}

当前使用

public Guid? InsertUpdate(News entity)
{
    return UsingSqlTransaction(sqlTrans => data.InsertUpdate(sqlTrans, entity));
}

解决方案-查看已接受的答案

public Guid? InsertUpdate(News entity)
{
    return UsingSqlTransaction(sqlTrans =>
    {
        var token = data.InsertUpdate(sqlTrans, entity);
        data.DoSomethingElse(sqlTrans, entity);
        return token;
    });
}
//-- The above UsingSqlTransaction remains unchanged

多个方法调用的函数委托

您可以使用'block'lambda。代替:

public Guid? InsertUpdate(News entity)
{
    return UsingSqlTransaction(sqlTrans => data.InsertUpdate(sqlTrans, entity));
}

您可以使用(注意大括号和分号):

public List<Guid?> InsertUpdate(News entity)
{
    return UsingSqlTransaction(sqlTrans =>
    {
        var result = new List<Guid?>();
        result.Add(data.InsertUpdate(sqlTrans, entity));
        result.Add(data.DoSomethingElse(sqlTrans, entity));
        return result;
    });
}

回复:您的更新。我会这样写(注意,你可以存储token并在lambda的末尾返回它,就像普通方法一样):

public Guid? InsertUpdate(News entity)
{
    return UsingSqlTransaction(sqlTrans =>
    {
        var token = data.InsertUpdate(sqlTrans, entity);
        data.DoSomethingElse(sqlTrans, entity);
        return token;
    });
}

我的程序中有相同的方法,但它是这样的:

void RunTransaction(Action<IDbCommand> action)
{
using(var cnn=GetConnection)
cnn.Open();
using(var trans=cnn.BeginTransaction())
{
var command=cnn.CreateCommand();
action(command);
trans.Commit();
}
}

此方法只负责管理事务,而不负责其他事务。它不在乎我们是在查询数据库还是在插入值。处理这些事情是调用者的责任,有了闭包的美妙之处,这是一项简单的任务:)

我的想法是:不要试图对所有东西都有一个抽象,因为很快你的程序员就会变得太复杂,无法扩展和维护。只要有一些基本的抽象可供使用,就可以在这些简单的抽象之上构建应用程序。

这是我成功使用过几次的模式:

拥有一个"事务管理器"对象,该对象在内部跟踪当前连接和事务。它可以是一个简单的静态,用于单线程应用程序,也可以使用线程本地存储甚至WCF操作上下文来做一些有趣的事情。其思想是,它为您提供了一个单独的位置来创建连接和事务,这些连接和事务与调用数据库的代码分离。

事务管理器公开一个名为BeginTransaction的公共方法,该方法返回实现IDisposable的事务对象。每次调用BeginTransaction时,都会得到一个新的事务范围实例。

事务范围对象还提供了获取数据库连接的方法,以及在处理之前必须调用的Commit方法。如果未调用Commit,则事务将在Dispose上回滚。

void M1() 
{
    using( var scope = TransactionManager.BeginTransaction() )
    {
      // Do stuff with the database.
      M2(); // M2 and M3 each create their own scopes that share the transaction
      M3(); // created by M1.
      // An exception before the commit will cause the transaction to roll back.
      scope.Commit();
    }
}

重要的是,TransactionManager将允许您创建嵌套的作用域——"对数据库做一些事情"行可以调用一组其他方法,每个方法都创建自己的作用域,共享一个事务。必须提交所有作用域,否则一切都将回滚。

这一切看起来都与System.Transactions命名空间中的东西的工作方式非常相似,我建议您也看看。

然后你的实用程序函数来简化代码,如果你仍然想要它们,看起来像这样:

public static void Execute(Action<ITransactionScope> action)
{
  using( var scope = TransactionManager.BeginTransaction() )
  {
    action(scope);
    scope.Commit();
  }
}
public static TResult Execute<TResult>(Func<ITransactionScope, TResult> func)
{
  using( var scope = TransactionManager.BeginTransaction() )
  {
    var result = func(scope);
    scope.Commit();
    return result;
  }
}