前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >《ASP.ENT Core 与 RESTful API 开发实战》-- (第5章)-- 读书笔记(中)

《ASP.ENT Core 与 RESTful API 开发实战》-- (第5章)-- 读书笔记(中)

作者头像
郑子铭
发布2021-01-13 15:43:10
7750
发布2021-01-13 15:43:10
举报
文章被收录于专栏:DotNet NB && CloudNative

第 5 章 使用 Entity Framework Core

5.3 重构仓储类

创建一个通用仓储接口

代码语言:javascript
复制
namespace Library.API.Services
{
    public interface IRepositoryBase<T>
    {
        Task<IEnumerable<T>> GetAllAsync();
        Task<IEnumerable<T>> GetByConditionAsync(Expression<Func<T, bool>> expression);
        void Create(T entity);
        void Update(T entity);
        void Delete(T entity);
        Task<bool> SaveAsync();
    }
}

继续创建一个接口

代码语言:javascript
复制
namespace Library.API.Services
{
    public interface IRepositoryBase2<T,TId>
    {
        Task<T> GetByIdAsync(TId id);
        Task<bool> IsExistAsync(TId id);
    }
}

添加 RepositoryBase 类并实现上面两个接口

代码语言:javascript
复制
namespace Library.API.Services
{
    public class RepositoryBase<T, TId> : IRepositoryBase<T>, IRepositoryBase2<T, TId> where T : class
    {
        public DbContext DbContext { get; set; }

        public RepositoryBase(DbContext dbContext)
        {
            DbContext = dbContext;
        }

        public Task<IEnumerable<T>> GetAllAsync()
        {
            return Task.FromResult(DbContext.Set<T>().AsEnumerable());
        }

        public Task<IEnumerable<T>> GetByConditionAsync(Expression<Func<T, bool>> expression)
        {
            return Task.FromResult(DbContext.Set<T>().Where(expression).AsEnumerable());
        }

        public void Create(T entity)
        {
            DbContext.Set<T>().Add(entity);
        }

        public void Update(T entity)
        {
            DbContext.Set<T>().Update(entity);
        }

        public void Delete(T entity)
        {
            DbContext.Set<T>().Remove(entity);
        }

        public async Task<bool> SaveAsync()
        {
            return await DbContext.SaveChangesAsync() > 0;
        }

        public async Task<T> GetByIdAsync(TId id)
        {
            return await DbContext.Set<T>().FindAsync(id);
        }

        public async Task<bool> IsExistAsync(TId id)
        {
            return await DbContext.Set<T>().FindAsync(id) != null;
        }
    }
}

这里需要注意的是,EF Core 对于查询的执行采用延迟执行的方法,只有遇到了实际需要结果的操作,查询才会执行,这些操作包括以下几种类型:

  • 对结果使用 for 或 foreach 循环
  • 使用了 ToList()、ToArray() 和 ToDictionary() 等方法
  • 使用了 Single()、Count()、Average、First() 和 Max() 等方法

创建其他仓储接口

代码语言:javascript
复制
public interface IAuthorRepository : IRepositoryBase<Author>, IRepositoryBase2<Author, Guid>

创建实现类

代码语言:javascript
复制
namespace Library.API.Services
{
    public class AuthorRepository : RepositoryBase<Author, Guid>, IAuthorRepository
    {
        public AuthorRepository(DbContext dbContext) : base(dbContext)
        {
        }
    }
}

以同样的方式创建 IBookRepository 与 BookRepository

接着创建仓储包装器 IRepositoryWrapper 及其实现

代码语言:javascript
复制
namespace Library.API.Services
{
    public interface IRepositoryWrapper
    {
        IBookRepository Book { get; }
        IAuthorRepository Author { get; }
    }
}

namespace Library.API.Services
{
    public class RepositoryWrapper : IRepositoryWrapper
    {
        public LibraryDbContext LibraryDbContext { get; }

        private IAuthorRepository _authorRepository = null;
        private IBookRepository _bookRepository = null;

        public RepositoryWrapper(LibraryDbContext libraryDbContext)
        {
            LibraryDbContext = libraryDbContext;
        }

        public IAuthorRepository Author => _authorRepository ?? new AuthorRepository(LibraryDbContext);
        public IBookRepository Book => _bookRepository ?? new BookRepository(LibraryDbContext);
    }
}

包装器提供了所有仓储接口的统一访问方式,从而避免了单独访问每个仓储接口

接下来要将包装器放到容器中,在 ConfigureServices 注入

代码语言:javascript
复制
services.AddScoped<IRepositoryWrapper, RepositoryWrapper>();
5.4 重构 Controller 和 Action

在重构之前,引入对象映射库 AutoMapper

代码语言:javascript
复制
Install-Package AutoMapper.Extensions.Microsoft.DependencyInjection

在 ConfigureServices 注入

代码语言:javascript
复制
services.AddAutoMapper(typeof(Startup));

为了 AutoMapper 正确执行对象映射,需要创建一个 Profile 类的派生类,用以说明映射的对象以及映射规则

代码语言:javascript
复制
namespace Library.API.Helpers
{
    public class LibraryMappingProfile : Profile
    {
        public LibraryMappingProfile()
        {
            CreateMap<Author, AuthorDto>()
                .ForMember(dest => dest.Age, config =>
                    config.MapFrom(src => src.BirthData.GetCurrentAge()));
            CreateMap<Book, BookDto>();
            CreateMap<AuthorForCreationDto, Author>();
            CreateMap<BookForCreationDto, Book>();
            CreateMap<BookForUpdateDto, Book>();
        }
    }
}

CreateMap 方法的两个泛型参数分别指明对象映射中的源和目标,当从数据库中获取数据时,实体类为源,而 DTO 为目标;当处理请求时相反

当程序运行时,执行 AddAutoMapper 方法时会扫描指定程序集中 Profile 类的派生类,并根据扫描结果生成映射规则

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2020-07-01,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 DotNet NB 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 第 5 章 使用 Entity Framework Core
    • 5.3 重构仓储类
      • 5.4 重构 Controller 和 Action
      相关产品与服务
      容器服务
      腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
      领券
      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档