Skip to content

Unit of Work

AlexLEWIS edited this page Sep 8, 2021 · 7 revisions

中文 | English

Unit of work can put multiple repositories into one unit for internal management and execution, and finally execute all operations through Commit. Unit of work internally uses database transactions.

static IFreeSql fsql = new FreeSql.FreeSqlBuilder()
    .UseConnectionString(FreeSql.DataType.MySql, connectionString)
    //Automatically synchronize the entity structure to the database.
    .UseAutoSyncStructure(true) 
    //Be sure to define as singleton mode
    .Build(); 

Usage

using (var uow = fsql.CreateUnitOfWork())
{
  var songRepo = fsql.GetRepository<Song>();
  var userRepo = fsql.GetRepository<User>();
  songRepo.UnitOfWork = uow; //Manually bind unit of work
  userRepo.UnitOfWork = uow;

  songRepo.Insert(new Song());
  userRepo.Update(...);

  uow.Orm.Insert(new Song()).ExecuteAffrows();
  //Note: uow.Orm and fsql are both IFreeSql
  //uow.Orm CRUD and uow are the same transaction (understood as temporary IFreeSql)
  //fsql CRUD and uow are not in the same transaction

  uow.Commit();
}

Reference: Use TransactionalAttribute + UnitOfWorkManager in ASP.NET Core to achieve multiple transaction propagation

Interface Definition

The uow.GetOrBeginTransaction() method can get the transaction object.

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