Skip to content

工作单元

2881099 edited this page Dec 3, 2020 · 32 revisions

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 是重写过的 IFreeSql 对象,它的 CRUD 与工作单元事务保持一致

  uow.Commit();
}

参考:在 asp.net core 中使用 TransactionalAttribute + UnitOfWorkManager 实现多种事务传播

接口定义

uow.GetOrBeginTransaction() 方法可获取事务对象。

public interface IUnitOfWork : IDisposable
{
  /// <summary>
  /// Select/Delete/Insert/Update/InsertOrUpdate 与工作单元事务保持一致,可省略传递 WithTransaction
  /// </summary>
  IFreeSql Orm { get; }

  /// <summary>
  /// 开启事务,或者返回已开启的事务
  /// </summary>
  /// <param name="isCreate">若未开启事务,则开启</param>
  /// <returns></returns>
  DbTransaction GetOrBeginTransaction(bool isCreate = true);

  IsolationLevel? IsolationLevel { get; set; }

  void Commit();

  void Rollback();

  /// <summary>
  /// 工作单元内的实体变化跟踪
  /// </summary>
  DbContext.EntityChangeReport EntityChangeReport { 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 操作都会最多触发一次该事件。

参考资料

Clone this wiki locally