-
Notifications
You must be signed in to change notification settings - Fork 893
工作单元
2881099 edited this page Dec 16, 2025
·
33 revisions
中文 | English
UnitOfWork 可将多个仓储放在一个单元管理执行,最终通用 Commit 执行所有操作,内部使用了数据库事务;
static IFreeSql fsql = new FreeSql.FreeSqlBuilder()
.UseConnectionString(FreeSql.DataType.MySql, connectionString)
.UseAutoSyncStructure(true) //自动同步实体结构到数据库
.Build(); //请务必定义成 Singleton 单例模式using (var uow = fsql.CreateUnitOfWork())
{
var songRepo = fsql.GetRepository<Song>();
var userRepo = fsql.GetRepository<User>();
songRepo.UnitOfWork = uow; //手工绑定工作单元
userRepo.UnitOfWork = uow;
songRepo.Insert(new Song());
userRepo.Update(...);
uow.Orm.Insert(new Song()).ExecuteAffrows();
//注意:uow.Orm 和 fsql 都是 IFreeSql
//uow.Orm CRUD 与 uow 是一个事务(理解为临时 IFreeSql)
//fsql CRUD 与 uow 不在一个事务
uow.Commit();
}参考:在 asp.net core 中使用 TransactionalAttribute + UnitOfWorkManager 实现多种事务传播
// 场景:已经有一个开启的 Connection 和 Transaction
using (var conn = new Microsoft.Data.SqlClient.SqlConnection("..."))
{
conn.Open();
using (var tran = conn.BeginTransaction())
{
// 1. 原生/Dapper 操作
// command.Transaction = tran;
// command.ExecuteNonQuery();
// 2. 桥接给 FreeSql
// 使用扩展方法创建适配器,传入现有的 tran
using (var uow = fsql.CreateUnitOfWork(tran))
{
// 在此 uow 下获取的仓储或 Orm,都会使用传入的 tran
var repo = uow.GetRepository<MyEntity>();
repo.Insert(new MyEntity { Name = "FreeSql Insert" });
// 或者直接使用 Orm
uow.Orm.Insert(new MyEntity { Name = "Direct Orm Insert" }).ExecuteAffrows();
// 这里的 Commit 只会触发 FreeSql 的事件,不会提交物理事务
uow.Commit();
}
// 3. 真正的提交由最外层控制
tran.Commit();
}
}uow.GetOrBeginTransaction() 方法可获取事务对象。
public interface IUnitOfWork : IDisposable
{
/// <summary>
/// 该对象 Select/Delete/Insert/Update/InsertOrUpdate 与工作单元事务保持一致,可省略传递 WithTransaction
/// </summary>
IFreeSql Orm { get; }
DbTransaction GetOrBeginTransaction(bool isCreate = true);
IsolationLevel? IsolationLevel { get; set; }
void Commit();
void Rollback();
/// <summary>
/// 工作单元内的实体变化跟踪
/// </summary>
DbContext.EntityChangeReport EntityChangeReport { get; }
/// <summary>
/// 用户自定义的状态数据,便于扩展
/// </summary>
Dictionary<string, object> States { get; }
}全局设置:
fsql.SetDbContextOptions(opt => {
opt.OnEntityChange = report => {
Console.WriteLine(report);
};
});单独设置:
var uow = fsql.CreateUnitOfWork();
uow.OnEntityChange = report => {
Console.WriteLine(report);
};参数 report 是一个 List 集合,集合元素的类型定义如下:
public class ChangeInfo {
public object Object { get; set; }
public EntityChangeType Type { get; set; }
/// <summary>
/// Type = Update 的时候,获取更新之前的对象
/// </summary>
public object BeforeObject { get; set; }
}
public enum EntityChangeType { Insert, Update, Delete, SqlRaw }| 变化类型 | 说明 |
|---|---|
| Insert | 实体对象被插入 |
| Update | 实体对象被更新 |
| Delete | 实体对象被删除 |
| SqlRaw | 执行了SQL语句 |
SqlRaw 目前有两处地方比较特殊:
- 多对多联级更新导航属性的时候,对中间表的全部删除操作;
- 通用仓储类 BaseRepository 有一个 Delete 方法,参数为表达式,而并非实体;
int Delete(Expression<Func<TEntity, bool>> predicate);DbContext.SaveChanges,或者 Repository 对实体的 Insert/Update/Delete,或者 UnitOfWork.Commit 操作都会最多触发一次该事件。