Skip to main content

UnitOfWork

nicyeAbout 1 minAbout 335 words

UnitOfWork

UnitOfWork is a wrapper around the DbTransaction transaction object, facilitating the management of private data.

How to Use

using (var uow = fsql.CreateUnitOfWork()) 
{
    await uow.Orm.Insert(item).ExecuteAffrowsAsync(); //uow.Orm API is the same as IFreeSql
    await uow.Orm.Ado.ExecuteNoneQueryAsync(sql);

    await fsql.Insert(item)... //Error, not within the same transaction

    var repo1 = uow.GetRepository<Song>();
    await repo1.InsertAsync(item);

    uow.Commit();
}

Tip: Within the uow scope, try not to use the fsql object to avoid being in different transactions.

Dependency Injection (Reference): Implementing Various Transaction Propagation with TransactionalAttribute + UnitOfWorkManager in ASP.NET Core

Interface Definition

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

public interface IUnitOfWork : IDisposable
{
    /// <summary>
    /// This object’s Select/Delete/Insert/Update/InsertOrUpdate will be consistent with the unit of work transaction; WithTransaction can be omitted.
    /// </summary>
    IFreeSql Orm { get; }

    DbTransaction GetOrBeginTransaction(bool isCreate = true);

    IsolationLevel? IsolationLevel { get; set; }

    void Commit();

    void Rollback();

    /// <summary>
    /// Entity change tracking within the unit of work
    /// </summary>
    DbContext.EntityChangeReport EntityChangeReport { get; }

    /// <summary>
    /// User-defined state data for extension
    /// </summary>
    Dictionary<string, object> States { get; }
}

Entity Change Events

Global Settings:

fsql.SetDbContextOptions(opt =>
{
    opt.OnEntityChange = report =>
    {
        Console.WriteLine(report);
    };
});

Individual Settings:

using (var uow = fsql.CreateUnitOfWork())
{
    uow.OnEntityChange = report => 
    {
        Console.WriteLine(report);
    };
}

The report parameter is a List collection, with the element types defined as follows:

public class ChangeInfo
{
    public object Object { get; set; }
    public EntityChangeType Type { get; set; }
    /// <summary>
    /// When Type = Update, get the object before the update
    /// </summary>
    public object BeforeObject { get; set; }
}
public enum EntityChangeType { Insert, Update, Delete, SqlRaw }
Change TypeDescription
InsertEntity object inserted
UpdateEntity object updated
DeleteEntity object deleted
SqlRawSQL statement executed

SqlRaw currently has two special cases:

  • When updating navigation properties in a many-to-many relationship, all delete operations on the junction table.
  • The generic repository class BaseRepository has a Delete method, with a parameter as an expression rather than an entity:
int Delete(Expression<Func<TEntity, bool>> predicate);

Repository operations for entity Insert/Update/Delete, or UnitOfWork.Commit operations will trigger this event at most once.