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


    第 5 章 使用 Entity Framework Core

    5.3 重构仓储类

    创建一个通用仓储接口

    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();
        }
    }
    

    继续创建一个接口

    namespace Library.API.Services
    {
        public interface IRepositoryBase2<T,TId>
        {
            Task<T> GetByIdAsync(TId id);
            Task<bool> IsExistAsync(TId id);
        }
    }
    

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

    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() 等方法

    创建其他仓储接口

    public interface IAuthorRepository : IRepositoryBase<Author>, IRepositoryBase2<Author, Guid>
    

    创建实现类

    namespace Library.API.Services
    {
        public class AuthorRepository : RepositoryBase<Author, Guid>, IAuthorRepository
        {
            public AuthorRepository(DbContext dbContext) : base(dbContext)
            {
            }
        }
    }
    

    以同样的方式创建 IBookRepository 与 BookRepository

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

    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 注入

    services.AddScoped<IRepositoryWrapper, RepositoryWrapper>();
    

    5.4 重构 Controller 和 Action

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

    Install-Package AutoMapper.Extensions.Microsoft.DependencyInjection
    

    在 ConfigureServices 注入

    services.AddAutoMapper(typeof(Startup));
    

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

    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 类的派生类,并根据扫描结果生成映射规则

    知识共享许可协议

    本作品采用知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议进行许可。

    欢迎转载、使用、重新发布,但务必保留文章署名 郑子铭 (包含链接: http://www.cnblogs.com/MingsonZheng/ ),不得用于商业目的,基于本文修改后的作品务必以相同的许可发布。

    如有任何疑问,请与我联系 (MingsonZheng@outlook.com) 。

  • 相关阅读:
    OpenMP并行程序设计
    Snmp在Windows下的实现WinSNMP编程原理
    利用C#开发基于snmpsharpnet基础的SNMP开发应用
    SNMP用VC实现的方法
    题目
    C# combox问题
    网络管理Snmp
    error BK1506
    响应activex事件
    使用C# 连接不同版本的Oracle.DataAccess
  • 原文地址:https://www.cnblogs.com/MingsonZheng/p/13217082.html
Copyright © 2020-2023  润新知