HTML5技术

Asp.Net Core 项目实战之权限管理系统(4) 依赖注入、仓储、服务的多项目分层实现 - Fonour

字号+ 作者:H5之家 来源:H5之家 2016-09-26 14:00 我要评论( )

0 Asp.Net Core 项目实战之权限管理系统(0) 无中生有 1 Asp.Net Core 项目实战之权限管理系统(1) 使用AdminLTE搭建前端 2 Asp.Net Core 项目实战之权限管理系统(2) 功能及实体设计 3 Asp.Net Core 项目实战之权限管理系统(3) 通过EntityFramework Co

0 Asp.Net Core 项目实战之权限管理系统(0) 无中生有

1 Asp.Net Core 项目实战之权限管理系统(1) 使用AdminLTE搭建前端

2 Asp.Net Core 项目实战之权限管理系统(2) 功能及实体设计

3 Asp.Net Core 项目实战之权限管理系统(3) 通过EntityFramework Core使用PostgreSQL

4 Asp.Net Core 项目实战之权限管理系统(4) 依赖注入、仓储、服务的多项目分层实现

5 Asp.Net Core 项目实战之权限管理系统(5) 用户登录

github源码地址

0 项目结构

写这个系列的最初目的其实只是为了自己能更好的学习Asp.Net Core,用一个小的系统作为练习,也督促自己。短期内不见得在实际项目中真的会运用,但至少通过学习,大致的对Asp.Net Core有个了解,也是为以后可能的应用做一下技术储备。起初的设想很简单,就是在一个Web项目中完成所有工作,大致了解Asp.Net Core的知识体系。

在实践的过程中不自觉的对这个练习的项目进行了一下分层。目前项目整体机构如下:

QQ图片20160924222505

项目说明:

  • Fonour.MVC
  •       Asp.Net Core MVC网站项目。

  • Fonour.Application
  •       应用服务项目,定义应用服务接口及实现,供Fonour.MVC控制器调用;同时定义接收及返回数据对象(Dto,这里我有可能会省去,直接拿实体往表现层传了……)

  • Fonour.Domain
  •       主要定义实体、仓储接口等。

  • Fonour.EntityFrameworkCore
  •       主要是仓储接口的EF Core具体实现

  • Fonour.Utility
  •       通用项目,定义项目无关的一些公共类库。

    1 仓储接口定义 1.0 基本接口定义

    仓储接口定义使用泛型接口,主要定义实体基本的增、删、改、查操作。在Fonour.Domain项目中新建一个名称为“IRepositories”的文件夹,在该文件夹中新建一个名称为“IRepository”的接口文件。暂时定义以下几个基本的接口,日后针对批量插入、删除、分页等操作再做进一步的完善。

    仓储接口定义 IRepository { } 定义泛型仓储接口 IRepository<TEntity, TPrimaryKey> : IRepository where TEntity : Entity<TPrimaryKey> { 获取实体集合 List<TEntity> GetAllList(); 根据lambda表达式条件获取实体集合 List<TEntity> GetAllList(Expression<Func<TEntity, bool>> predicate); 根据主键获取实体 TEntity Get(TPrimaryKey id); 根据lambda表达式条件获取单个实体 TEntity FirstOrDefault(Expression<Func<TEntity, bool>> predicate); 新增实体 TEntity Insert(TEntity entity); 更新实体 TEntity Update(TEntity entity); 新增或更新实体 TEntity InsertOrUpdate(TEntity entity); 删除实体 Delete(TEntity entity); 删除实体 Delete(TPrimaryKey id); }

    这个练习项目使用的是Guid类型的主键,为方便使用,再继承定义一个主键类型为Guid的接口。

    默认Guid主键类型仓储 IRepository<TEntity> : IRepository<TEntity, Guid> where TEntity : Entity { }

    1.1 用户管理仓储接口定义

    如无特殊操作需要,我们的基础接口基本上能够满足各类实体共性的增删改查操作。对于某种实体特有的操作,就需要单独进行操作接口的定义。比如后面我们要实现用户登录的验证功能,即提供用户名、密码,验证该用户是否存在,以及用户名密码是否正确。对于此类特定需求,我们针对用户实体定义一个用户管理的仓储接口。

    在“IRepositories”文件夹下新建一个名称为“IUserRepository”的接口,里面暂时只定义一个检查用户是否存在的方法,做为我们最后的测试接口。

    用户管理仓储接口 IUserRepository : IRepository<User> { 检查用户是存在 User CheckUser(string userName, string password); }

    QQ图片20160924225551

    2 仓储接口实现

    仓储接口的实现全部放在Fonour.EntityFrameworkCore项目中,通过EF Core使用PostgresSQL数据库实现。

    2.0 基本接口实现

    在Fonour.EntityFrameworkCore项目中新建一个名称为“Repositories”的文件夹,在文件夹中添加一个名称为“FonourRepositoryBase”的抽象类。

    该抽象类除了实现基本仓储接口定义的方法外,还有2个需要注意的地方。、

    1 定义了数据访问上下文对象

    该数据访问上下文对象通过构造函数进行依赖注入,Asp.Net Core已经默认对数据访问上下文对象进行了构造函数依赖注入的实现,具体应用后面会说到。

    2 定义了一个Save操作方法

    目的为了在应用服务层调用多个仓储后,统一进行数据上下文的SaveChanges操作,保证数据存储的事务性。

    仓储基类 FonourRepositoryBase<TEntity, TPrimaryKey> : IRepository<TEntity, TPrimaryKey> where TEntity : Entity<TPrimaryKey> { FonourDbContext _dbContext; 通过构造函数注入得到数据上下文对象实例 FonourRepositoryBase(FonourDbContext dbContext) { _dbContext = dbContext; } 获取实体集合 List<TEntity> GetAllList() { return _dbContext.Set<TEntity>().ToList(); } 根据lambda表达式条件获取实体集合 List<TEntity> GetAllList(Expression<Func<TEntity, bool>> predicate) { return _dbContext.Set<TEntity>().Where(predicate).ToList(); } 根据主键获取实体 TEntity Get(TPrimaryKey id) { return _dbContext.Set<TEntity>().FirstOrDefault(CreateEqualityExpressionForId(id)); } 根据lambda表达式条件获取单个实体 TEntity FirstOrDefault(Expression<Func<TEntity, bool>> predicate) { return _dbContext.Set<TEntity>().FirstOrDefault(predicate); } 新增实体 TEntity Insert(TEntity entity) { _dbContext.Set<TEntity>().Add(entity); return entity; } 更新实体 TEntity Update(TEntity entity) { _dbContext.Set<TEntity>().Attach(entity); _dbContext.Entry(entity).State = EntityState.Modified; return entity; } 新增或更新实体 TEntity InsertOrUpdate(TEntity entity) { if (Get(entity.Id) != null) return Update(entity); return Insert(entity); } 删除实体 Delete(TEntity entity) { _dbContext.Set<TEntity>().Remove(entity); } 删除实体 Delete(TPrimaryKey id) { _dbContext.Set<TEntity>().Remove(Get(id)); } 事务性保存 Save() { _dbContext.SaveChanges(); } 根据主键构建判断表达式 Expression<Func<TEntity, bool>> CreateEqualityExpressionForId(TPrimaryKey id) { var lambdaParam = Expression.Parameter(typeof(TEntity)); var lambdaBody = Expression.Equal( Expression.PropertyOrField(lambdaParam, ), Expression.Constant(id, typeof(TPrimaryKey)) ); return Expression.Lambda<Func<TEntity, bool>>(lambdaBody, lambdaParam); } }

    同样的实现一个主键类型为Guid的仓储操作基类。

     

    1.本站遵循行业规范,任何转载的稿件都会明确标注作者和来源;2.本站的原创文章,请转载时务必注明文章作者和来源,不尊重原创的行为我们将追究责任;3.作者投稿可能会经我们编辑修改或补充。

    相关文章
    • asp.net mvc signalr 简单聊天室 - liuhz

      asp.net mvc signalr 简单聊天室 - liuhz

      2016-09-25 17:02

    • ASP.NET Core MVC 配置全局路由前缀 - Savorboard

      ASP.NET Core MVC 配置全局路由前缀 - Savorboard

      2016-09-25 11:00

    • 使用签名来保证ASP.NET MVC OR WEBAPI的接口安全 - Agile.Zhou

      使用签名来保证ASP.NET MVC OR WEBAPI的接口安全 - Agile.Zhou

      2016-09-24 17:00

    • 使用 Entity Framework Core 时,通过代码自动 Migration - JRoger

      使用 Entity Framework Core 时,通过代码自动 Migration - JRoger

      2016-09-04 17:00

    网友点评