31

在 Dapper中使用BeginTransaction()with的正确方法是什么?IDbConnection

我创建了一个我必须使用的方法BeginTransaction()。这是代码。

using (IDbConnection cn = DBConnection)
{
    var oTransaction = cn.BeginTransaction();

    try
    {
        // SAVE BASIC CONSULT DETAIL
        var oPara = new DynamicParameters();
        oPara.Add("@PatientID", iPatientID, dbType: DbType.Int32);
        ..........blah......blah............
    }
    catch (Exception ex)
    {
        oTransaction.Rollback();
        return new SaveResponse { Success = false, ResponseString = ex.Message };
    }
}

当我执行上述方法时-我遇到了异常-

无效操作。连接已关闭。

这是因为您无法在连接打开之前开始事务。所以当我添加这一行时:cn.Open();,错误得到解决。但是我在某处读到手动打开连接是不好的做法!Dapper 仅在需要时打开连接。

在实体框架中,您可以使用TransactionScope.

cn.Open()...所以我的问题是什么是处理事务而不在Dapper中添加行的好习惯?我想应该有一些适当的方法。

4

4 回答 4

65

手动打开连接并不是“坏习惯”;dapper 可以方便地使用打开或关闭的连接,仅此而已。一个常见的问题是人们的连接处于打开状态、未使用状态、时间过长而从未将它们释放到池中 - 但是,在大多数情况下这不是问题,您当然可以这样做:

using(var cn = CreateConnection()) {
    cn.Open();
    using(var tran = cn.BeginTransaction()) {
        try {
            // multiple operations involving cn and tran here

            tran.Commit();
        } catch {
            tran.Rollback();
            throw;
        }
    }
}

请注意,dapper 有一个可选参数可以传入事务,例如:

cn.Execute(sql, args, transaction: tran);

我实际上很想IDbTransaction该工作上使用类似的扩展方法,因为事务总是暴露.Connection;这将允许:

tran.Execute(sql, args);

但这在今天不存在。

TransactionScope是另一种选择,但具有不同的语义:这可能涉及 LTM 或 DTC,主要取决于......好吧,运气。IDbTransaction创建一个不需要try/的包装器也很诱人catch- 更像是如何TransactionScope工作的;类似的东西(这也不存在):

using(var cn = CreateConnection())
using(var tran = cn.SimpleTransaction())
{
    tran.Execute(...);
    tran.Execute(...);

    tran.Complete();
}
于 2014-07-09T12:29:43.680 回答
6

你不应该打电话

cn.Close();

因为 using 块也会尝试关闭。对于事务部分,是的,您也可以使用 TransactionScope,因为它不是与实体框架相关的技术。看看这个 SO 答案:https ://stackoverflow.com/a/6874617/566608 它解释了如何在事务范围内登记您的连接。重要的方面是:连接会自动加入事务 IIF 您在范围内打开连接

于 2014-07-09T10:06:06.130 回答
4

看看Tim Schreiber解决方案,它简单但功能强大,使用存储库模式实现并Dapper Transactions牢记在心。

下面Commit()的代码中显示了它。

public class UnitOfWork : IUnitOfWork
{
    private IDbConnection _connection;
    private IDbTransaction _transaction;
    private IBreedRepository _breedRepository;
    private ICatRepository _catRepository;
    private bool _disposed;

    public UnitOfWork(string connectionString)
    {
        _connection = new SqlConnection(connectionString);
        _connection.Open();
        _transaction = _connection.BeginTransaction();
    }

    public IBreedRepository BreedRepository
    {
        get { return _breedRepository ?? (_breedRepository = new BreedRepository(_transaction)); }
    }

    public ICatRepository CatRepository
    {
        get { return _catRepository ?? (_catRepository = new CatRepository(_transaction)); }
    }

    public void Commit()
    {
        try
        {
            _transaction.Commit();
        }
        catch
        {
            _transaction.Rollback();
            throw;
        }
        finally
        {
            _transaction.Dispose();
            _transaction = _connection.BeginTransaction();
            resetRepositories();
        }
    }

    private void resetRepositories()
    {
        _breedRepository = null;
        _catRepository = null;
    }

    public void Dispose()
    {
        dispose(true);
        GC.SuppressFinalize(this);
    }

    private void dispose(bool disposing)
    {
        if (!_disposed)
        {
            if(disposing)
            {
                if (_transaction != null)
                {
                    _transaction.Dispose();
                    _transaction = null;
                }
                if(_connection != null)
                {
                    _connection.Dispose();
                    _connection = null;
                }
            }
            _disposed = true;
        }
    }

    ~UnitOfWork()
    {
        dispose(false);
    }
}
于 2017-03-30T22:06:06.733 回答
0

Dapper 有两种使用交易的预期方式。

  1. 将您的电话传递IDbTranasction给您的正常 Dapper 电话。

    前:

    var affectedRows = connection.Execute(sql, new {CustomerName = "Mark"});
    

    后:

    var affectedRows = connection.Execute(sql, new {CustomerName = "Mark"}, transaction=tx);
    
  2. .Execute使用Dapper 添加到IDbTransaction自身的新扩展方法:

    tx.Execute(sql, new {CustomerName = "Mark"});
    

注意:变量tx来自IDbTransaction tx = connection.BeginTransaction();

这就是你应该如何使用 Dapper 的交易方式;它们都不是 TransactionScope。

奖金阅读

于 2021-11-12T13:12:06.160 回答