Skip to main content

Unit of Work Manager

nicyeAbout 1 minAbout 420 words

Unit of Work Manager

Use FreeSql's repository transaction in ASP.NET Core

Step 1: Configure Startup.cs

Install NuGet packages:

dotnet add package FreeSql
dotnet add package FreeSql.DbContext
dotnet add package FreeSql.Provider.MySqlConnector

Configure Startup.cs:

public void ConfigureServices(IServiceCollection services)
{
  IConfigurationSection Mysql = Configuration.GetSection("Mysql");
        Fsql = new FreeSqlBuilder()
            .UseConnectionString(DataType.MySql, Mysql.Value)
            .UseAutoSyncStructure(true)
            .UseNameConvert(NameConvertType.PascalCaseToUnderscoreWithLower)
            .UseMonitorCommand(cmd => Trace.WriteLine(cmd.CommandText))
            .Build();
    services.AddSingleton<IFreeSql>(fsql);
    services.AddScoped<UnitOfWorkManager>();
    services.AddFreeRepository(null, typeof(Startup).Assembly);
    //Add your own service, here is only an implementation
    services.AddScoped<TransBlogService>();
}

Update your appsettings.json:

{
  "Mysql": "Data Source=127.0.0.1;Port=3306;User ID=root;Password=root;Initial Catalog=ovov_freesql_repository;Charset=utf8;SslMode=none;Max pool size=10",
}
UnitOfWorkManager MembersDescription
IUnitOfWork CurrentReturn the current unit of work
void Binding(repository)Hand over repository transaction to ir for management
IUnitOfWork Begin(propagation, isolationLevel)Create unit of work
  • TransBlogService.cs
private readonly IBaseRepository<Blog, int> _blogRepository;
private readonly IBaseRepository<Tag, int> _tagRepository;
private readonly UnitOfWorkManager _unitOfWorkManager;

public TransBlogService(IBaseRepository<Blog, int> blogRepository, IBaseRepository<Tag, int> tagRepository,UnitOfWorkManager unitOfWorkManager)
{
    _blogRepository = blogRepository ;
    _tagRepository = tagRepository ;
    _unitOfWorkManager = unitOfWorkManager;
}

public async Task CreateBlogUnitOfWorkAsync(Blog blog,List<Tag>tagList)
{
    using (IUnitOfWork unitOfWork = _unitOfWorkManager.Begin())
    {
        try
        {
            await _blogRepository.InsertAsync(blog);
            tagList.ForEach(r =>
            {
                r.PostId = blog.Id;
            });
            await _tagRepository.InsertAsync(tagList);
            unitOfWork.Commit();
        }
        catch (Exception e)
        {     
            //Actually, Rollback may not be used. 
            //Because the internal Dispose of IUnitOfWork will roll back the transaction without Commit. 
            //But here can be Rollback in advance.
        
            unitOfWork.Rollback();
            //Log, 
            //or use throw to continue throwing exceptions upwards
        }
    }
}

public async Task UpdateBlogAsync(int id)
{
    using (IUnitOfWork unitOfWork = _unitOfWorkManager.Begin())
    {
        try
        {
            Blog blog = _blogRepository.Select.Where(r => r.Id == id).First();
            blog.IsDeleted = true;
            await _blogRepository.UpdateAsync(blog);
            unitOfWork.Commit();
        }
        catch (Exception e)
        {
            //Log, 
            //or use throw to continue throwing exceptions upwards
            unitOfWork.Rollback();
        }
    }
}
IUnitOfWork MembersDescription
IFreeSql OrmThe object Select/Delete/Insert/Update/InsertOrUpdate is consistent with the unit of work transaction and can be omitted to pass WithTransaction
DbTransaction GetOrBeginTransaction()Open the transaction, or return to the opened transaction
void Commit()Commit transaction
void Rollback()Rollback transaction
DbContext.EntityChangeReport EntityChangeReportEntity change tracking within the unit of work

Complete code

The above uses generic repository.

If you want to rewrite a repository, how do you keep the same transaction as UnitOfWorkManager? You can inherit the existing DefaultRepository<,> and implement a custom repository BlogRepository.cs:

    public class BlogRepository : DefaultRepository<Blog, int>, IBlogRepository
    {
        public BlogRepository(UnitOfWorkManager uowm) : base(uowm?.Orm, uowm)
        {
        }

        public List<Blog> GetBlogs()
        {
            return Select.Page(1, 10).ToList();
        }
    }

The interface is IBlogRepository.cs:

    public interface IBlogRepository : IBaseRepository<Blog, int>
    {
        List<Blog> GetBlogs();
    }

Inject this service in startup.cs

    services.AddScoped<IBlogRepository, BlogRepository>();