Dapper不内置工作单元模式,但可自行封装UnitOfWork类统一管理连接与事务,通过IUnitOfWork接口解耦仓储,显式控制BeginTransaction/Commit/Rollback,确保操作原子性与可测试性。
Dapper 本身不内置工作单元(Unit o
f Work)模式,但你可以用轻量、可控的方式自己封装,实现事务一致性与仓储解耦。关键在于统一管理数据库连接、事务和命令执行时机——不是靠框架自动注入,而是靠设计把“一批操作当一个原子”来处理。
不要让每个仓储自己开连接或事务。建一个 UnitOfWork 类,持有 IDbConnection 和可选的 IDbTransaction,所有仓储通过它获取连接(带事务),提交/回滚也只由它控制。
BeginTransaction()),不默认开启UserRepository)接收 IUnitOfWork 而非 IDbConnection,确保用的是同一连接和事务以下是一个最小可行的 UnitOfWork 实现:
public interface IUnitOfWork : IDisposable
{
IDbConnection Connection { get; }
IDbTransaction Transaction { get; }
void BeginTransaction();
void Commit();
void Rollback();
}
public class UnitOfWork : IUnitOfWork
{
private readonly IDbConnection _connection;
public IDbConnection Connection => _connection;
public IDbTransaction Transaction { get; private set; }
public UnitOfWork(string connectionString)
{
_connection = new SqlConnection(connectionString);
_connection.Open();
}
public void BeginTransaction() => Transaction = _connection.BeginTransaction();
public void Commit() => Transaction?.Commit();
public void Rollback() => Transaction?.Rollback();
public void Dispose()
{
Transaction?.Dispose();
_connection?.Dispose();
}
}
使用时:
using var uow = new UnitOfWork("conn-str");
uow.BeginTransaction();
var userRepo = new UserRepository(uow);
var orderRepo = new OrderRepository(uow);
userRepo.Insert(new User { Name = "Alice" });
orderRepo.Insert(new Order { UserId = 1, Amount = 100 });
uow.Commit(); // 一起提交,失败则全部回滚
定义仓储接口,让具体实现只依赖 IUnitOfWork:
public interface IUserRepository
{
void Insert(User user);
User GetById(int id);
}
public class UserRepository : IUserRepository
{
private readonly IUnitOfWork _uow;
public UserRepository(IUnitOfWork uow) => _uow = uow;
public void Insert(User user)
{
const string sql = "INSERT INTO Users (Name) VALUES (@Name); SELECT CAST(SCOPE_IDENTITY() as int)";
user.Id = _uow.Connection.QuerySingle(sql, user, _uow.Transaction);
}
}
这样测试时可 mock IUnitOfWork,业务逻辑不绑定具体数据库类型。
Open() 或 Close() —— 连接生命周期由 UnitOfWork 管理BeginTransactionAsync、CommitAsync,并用 ExecuteAsync 替代同步方法Commit() 更清晰,防止遗漏或误提交基本上就这些。Dapper 的简洁性正是优势——工作单元不用重造轮子,几行代码就能稳稳兜住事务边界。