Asp.Net Core API +EF+Sqllite+Automapper+搭建后端服务 系列(四)引入工作单元(UnitOfWork) 创建Repository

接上篇我们配置DBContext,配章节继续搭建工作单元、创建仓储、构建数据更新查询等业务逻辑服务。

gitee:NoteList: 项目使用WPF Prism MaterialDesign WebApi 基本功能 创建任务 记录任务状态 及相关统计功能 WPF (gitee.com)

1、工作单元和仓储

使用仓储模式是为了分离业务层和数据源层,并实现业务层的Model和数据源层的Model映射。即业务逻辑层应该和数据源层无关,业务层只关心结果,数据源层关心细节。

数据源层和业务层之间的分离有三个好处:

  • 集中了数据逻辑或Web服务访问逻辑。
  • 为单元测试提供了一个替代点。
  • 提供了一种灵活的体系结构,可以作为应用程序的整体设计进行调整

工作单元模式:用来维护一个已经被业务事务修改(CURD操作)的业务对象列表。工作单元模式负责协调这些修改的持久化工作以及所有标记的并发问题。采用工作单元模式带来的好处是能够保证数据的完整性。如果在持久化一系列业务对象的过程中出现问题,则将所有的修改回滚,以保证数据始终处于有效状态。简单来说,工作单元模式就是把业务对象的持久化由工作单元实现类进行统一管理。而不想之前那样,分布在每个具体的仓储类中,这样就可以达到一系列业务对象的统一管理,不至于在每个业务对象中出现统一的提交和回滚业务逻辑,实现代码最大化重用。

  简单概括就是:对某个业务操作,比如银行的进出账的业务对象(进账对象,出账对象)进行统一管理,使它们不需要在自己的repository中提交(commit),放在工作单元中做持久化工作

git上有成熟的工作单元模式封装我们使用:Arch/UnitOfWork: A plugin for Microsoft.EntityFrameworkCore to support repository, unit of work patterns, multiple database with distributed transaction supported, and MySQL multiple databases/tables sharding supported. (github.com)

引入代码后封装TodoRepository

 public class UserRepository : Repository<User>
    {
        public UserRepository(MyToDoContext dbContext) : base(dbContext)
        {
        }
    }

为了解决耦合的业务代码引用多个Repository, 在Repository和Controller 中间加一次Service曾将主要业务代码是现在Service曾,Controller对外提供完整的业务接口,基本不实现业务代码

首先定义IBaseSevice接口,定义增删改查业务方法

 public interface IBaseSevice<TDto,T> where T : class
    {
        Task<ApiResponse> AddAsync(TDto  dto);
        Task<ApiResponse> UpdateAsync(TDto dto);
        Task<ApiResponse> GetAsync();
        Task<ApiResponse> GetById(int id);
        Task<ApiResponse> Delete(int id);
    }

BaseService实现IBaseSevice,此处不具体实现UpdateAsync方法,在具体的业务Service中实现更新业务代码。

 public class BaseService<TDto, T> : IBaseSevice<TDto, T> where TDto : BaseDto where T : BaseEntity
    {
        private readonly IUnitOfWork unitOfWork;
        private readonly IMapper mapper;

        public BaseService(IUnitOfWork unitOfWork, IMapper mapper)
        {
            this.unitOfWork = unitOfWork;
            this.mapper = mapper;
        }

        public async Task<ApiResponse> AddAsync(TDto dto)
        {
            try
            {
                var entity = mapper.Map<T>(dto);
                await unitOfWork.GetRepository<T>().InsertAsync(entity);
                var result = await unitOfWork.SaveChangesAsync();
                if (result > 0)
                {
                    return new ApiResponse(true, entity);
                }
                else
                {
                    return new ApiResponse(false, "保存失败");
                }
            }
            catch (Exception ex)
            {
                return new ApiResponse(false, ex.Message);
            }
        }

        public async Task<ApiResponse> Delete(int id)
        {
            try
            {
                //删除
                var repository = unitOfWork.GetRepository<TDto>();
                var entity = await repository.GetFirstOrDefaultAsync(predicate: x => x.ID.Equals(id));
                if (entity != null)
                {
                    repository.Delete(entity);
                }
                //保存
                var result = await unitOfWork.SaveChangesAsync();
                if (result > 0)
                {
                    return new ApiResponse(true, "");
                }
                else
                {
                    return new ApiResponse(false, "删除失败");
                }
            }
            catch (Exception ex)
            {
                return new ApiResponse(false, "删除失败" + ex.Message);
            }
        }

        public async Task<ApiResponse> GetAsync()
        {
            try
            {
                var repository = unitOfWork.GetRepository<TDto>();
                var results = await repository.GetAllAsync();
                return new ApiResponse(true, results);
            }
            catch (Exception ex)
            {
                return new ApiResponse(false, ex.Message);
            }
        }


        public async Task<ApiResponse> GetById(int id)
        {
            try
            {
                //删除
                var repository = unitOfWork.GetRepository<TDto>();
                var entity = await repository.GetFirstOrDefaultAsync(predicate: x => x.ID.Equals(id));
                return new ApiResponse(true, entity);
            }
            catch (Exception ex)
            {
                return new ApiResponse(false, "删除失败" + ex.Message);
            }
        }

        public Task<ApiResponse> UpdateAsync(TDto entity)
        {
            throw new NotImplementedException();
        }
    }

定义IToDoService 继承IBaseService接口

 public interface IToDoService : IBaseSevice<ToDoDto, ToDo>
    {
    }

ToDoService实现IToDoService并重写UpdateAsync

 public class ToDoService : BaseService<ToDoDto, ToDo>, IToDoService
    {
        private readonly IUnitOfWork unitOfWork;
        private readonly IMapper mapper;

        public ToDoService(IUnitOfWork unitOfWork, IMapper mapper) : base(unitOfWork, mapper)
        {
            this.unitOfWork = unitOfWork;
            this.mapper = mapper;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="toDo"></param>
        /// <returns></returns>
        new public async Task<ApiResponse> UpdateAsync(ToDoDto toDodto)
        {
            try
            {
                var todo = mapper.Map<ToDo>(toDodto);
                var repository = unitOfWork.GetRepository<ToDo>();
                var todoEntity = await repository.GetFirstOrDefaultAsync(predicate: x => x.ID.Equals(todo.ID));
                if (todoEntity != null)
                {
                    todoEntity.Titile = todo.Titile;
                    todoEntity.Description = todo.Description;
                    todoEntity.Status = todo.Status;
                    todoEntity.UpdateTime = DateTime.Now;
                }
                repository.Update(todoEntity);
                var result = await unitOfWork.SaveChangesAsync();
                if (result > 0)
                {
                    return new ApiResponse(true, todoEntity);
                }
                else
                {
                    return new ApiResponse(false, "保存失败");
                }
            }
            catch (Exception ex)
            {
                return new ApiResponse(false, ex.Message);
            }
        }
    }

在StartUp中注册仓储和服务层接口

services.AddCustomRepository<ToDo, ToDoRepository>();
 services.AddTransient<IToDoService, ToDoService>();

创建ToDoController

[ApiController]
    [Route("api/[controller]/[action]")]
    public class ToDoController : Controller
    {
        private readonly IToDoService todoService;

        public ToDoController(IToDoService todoService)
        {
            this.todoService = todoService;
        }

        [HttpGet]
        public async Task<ApiResponse> GetByIdAsync(int id) => await todoService.GetById(id);

        [HttpGet]
        public async Task<ApiResponse> GetAllAsync() => await todoService.GetAsync();

        [HttpPost]
        public async Task<ApiResponse> AddAsync([FromBody] ToDoDto toDo) => await todoService.AddAsync(toDo);

        [HttpPost]
        public async Task<ApiResponse> UpdateAsync([FromBody] ToDoDto toDo) => await todoService.UpdateAsync(toDo);

        [HttpDelete]
        public async Task<ApiResponse> DeleteAsync(int id) => await todoService.Delete(id);

    }

 

posted @ 2022-02-25 15:00  吃葡萄不吐葡萄脾  阅读(400)  评论(0编辑  收藏  举报