在前面随笔,我介绍了整个ABP优化过框架的分层模型,包括尽可能简化整个ABP框架的各个层的关系,以及归入一些基类的辅助处理,使得咱们对应业务分层类或者接口尽量减小代码,并具备生产环境所须要的基类接口,经过我对整个ABP框架模型的分析,咱们能够结合代码生成工具Database2Sharp来生成对应分层的代码,该工具后台具有数据库表所须要的一切字段信息和关系信息,所以咱们肯定好逻辑关系就能够生成对应分层的代码。本篇随笔介绍代码生成工具Database2Sharp生成基于ABP框架的分层代码过程。html
ABP框架主要仍是基于领域驱动的理念来构建整个架构的,其中领域驱动包含的概念有 域对象Entities、仓储对象Repositories、域服务接口层Domain Services、域事件Domain Events、应用服务接口Application Services、数据传输对象DTOs等。数据库
如下是ABP初始框架的各个分层的信息,它主要是分为下面几个项目分层。架构
Application应用层:应用层提供一些应用服务(Application Services)方法供展示层调用。一个应用服务方法接收一个DTO(数据传输对象)做为输入参数,使用这个输入参数执行特定的领域层操做,并根据须要可返回另外一个DTO。app
Core领域核心层,领域层就是业务层,是一个项目的核心,全部业务规则都应该在领域层实现。这个项目里面,除了定义所需的领域实体类外,其实能够定义咱们本身的自定义的仓储对象(相似DAL/IDAL),以及定义本身的业务逻辑层(相似BLL/IBLL),以及基于AutoMapper映射规则等内容。框架
EntityFrameworkCore 实体框架核心层,这个项目不须要修改太多内容,只须要在DbContext里面加入对应领域对象的仓储对象便可。ide
Migrator数据迁移层,这个是一个辅助建立的控制台程序项目,若是基于DB First,咱们能够利用它来建立咱们项目的初始化数据库。函数
Web.Core Web核心层,基于Web或者Web API的核心层,提供了对身份登录验证的基础处理,没有其余内容。工具
Web.Core.Host Web API的宿主层,也是动态发布Web API的核心内容,另外在Web API里面整合了Swagger,使得咱们能够方便对Web API的接口进行调试。post
Tests 单元测试层,这个提供了一些应用层对象的模拟测试,其中测试的数据库使用的是Entity Framework 的内存数据库,不影响实际数据库内容。单元测试
通过我进行简化和优化处理的框架项目结构以下所示。
以上是VS里面解决方案的项目结构,我根据项目之间的关系,整理了一个架构的图形,以下所示。
上图是以字典模块为介绍, 其中橘红色的部分就是咱们为各个分层须要根据数据库构建对应的类或者接口文件。
例如对于01-Core模块层,须要增长文件
对于03-Application.Common模块来讲,须要增长DTO和应用服务层接口文件
而对于04-Application应用层来讲,须要增长对应的接口实现文件
而0五、0六、07模块,咱们不须要加入任何文件,08-Caller层加入对WebAPI的远程调用封装类,给Winform、WPF/UWP、控制台程序等调用。
一个模块的变化,都会致使在上面各个分层之间增长对应的文件,这样的架构肯定后,咱们就能够根据对应的类生成规则进行生成接口。
在前面随笔《代码生成工具Database2Sharp的架构介绍》中,我介绍了整个代码生成工具的架构信息,所以咱们用代码生成工具生成架构代码的时候,能够利用整个数据库表的信息和关系信息来处理。
经过整合相关的生成规则,咱们能够增长对应的ABP框架代码的生成,以下代码生成工具界面所示。
最终根据根据选择数据库表信息,一键生成相关ABP架构分层代码,文件结构以下所示。
对比前面项目的介绍,咱们能够看到各个分层的类代码是彻底一致的。如对于领域层,包含了表名称标记、字段信息和引用外键的对象。
/// <summary> /// 通用字典明细项目信息,领域对象 /// </summary> [Table("TB_DictData")] public class DictData : FullAuditedEntity<string> { /// <summary> /// 默认构造函数(须要初始化属性的在此处理) /// </summary> public DictData() { } #region Property Members /// <summary> /// 字典大类 /// </summary> //[Required] public virtual string DictType_ID { get; set; } /// <summary> /// 字典名称 /// </summary> //[Required] public virtual string Name { get; set; } /// <summary> /// 字典值 /// </summary> public virtual string Value { get; set; } /// <summary> /// 备注 /// </summary> public virtual string Remark { get; set; } /// <summary> /// 排序 /// </summary> public virtual string Seq { get; set; } /// <summary> /// 字典大类 /// </summary> [ForeignKey("DictType_ID")] public virtual DictType DictType { get; set; } #endregion }
对于DTO文件,咱们看看代码信息
/// <summary> /// 通用字典明细项目信息,DTO对象 /// </summary> public class DictDataDto { /// <summary> /// 默认构造函数(须要初始化属性的在此处理) /// </summary> public DictDataDto() { } #region Property Members /// <summary> /// 字典大类 /// </summary> public virtual string DictType_ID { get; set; } /// <summary> /// 字典名称 /// </summary> public virtual string Name { get; set; } /// <summary> /// 字典值 /// </summary> //[Required] public virtual string Value { get; set; } /// <summary> /// 备注 /// </summary> public virtual string Remark { get; set; } /// <summary> /// 排序 /// </summary> public virtual string Seq { get; set; } #endregion } /// <summary> /// 建立通用字典明细项目信息,DTO对象 /// </summary> public class CreateDictDataDto : DictDataDto { } /// <summary> /// 用于根据条件分页查询,DTO对象 /// </summary> public class DictDataPagedDto : PagedResultRequestDto { public DictDataPagedDto() { } /// <summary> /// 参数化构造函数 /// </summary> /// <param name="skipCount">跳过的数量</param> /// <param name="resultCount">最大结果集数量</param> public DictDataPagedDto(int skipCount, int resultCount) { this.SkipCount = skipCount; this.MaxResultCount = resultCount; } /// <summary> /// 使用分页信息进行初始化SkipCount 和 MaxResultCount /// </summary> /// <param name="pagerInfo">分页信息</param> public DictDataPagedDto(PagerInfo pagerInfo) { if (pagerInfo != null) { //默认设置 var pageSize = pagerInfo.PageSize > 0 ? pagerInfo.PageSize : 50; var pageIndex = pagerInfo.CurrenetPageIndex > 0 ? pagerInfo.CurrenetPageIndex : 1; this.SkipCount = pageSize * (pageIndex - 1); this.MaxResultCount = pageSize; } } #region Property Members /// <summary> /// 字典大类 /// </summary> public virtual string DictType_ID { get; set; } /// <summary> /// 字典名称 /// </summary> public virtual string Name { get; set; } /// <summary> /// 字典值 /// </summary> public virtual string Value { get; set; } /// <summary> /// 备注 /// </summary> public virtual string Remark { get; set; } /// <summary> /// 排序 /// </summary> public virtual string Seq { get; set; } #endregion }
DTO的映射文件代码生成以下
/// <summary> /// 通用字典明细项目信息,映射文件 /// </summary> public class DictDataMapProfile : Profile { public DictDataMapProfile() { CreateMap<DictDataDto, DictData>(); CreateMap<DictData, DictDataDto>(); CreateMap<CreateDictDataDto, DictData>(); } }
应用服务层接口实现代码以下所示。
/// <summary> /// 通用字典明细项目信息,应用层服务接口实现 /// </summary> [AbpAuthorize] public class DictDataAppService : MyAsyncServiceBase<DictData, DictDataDto, string, DictDataPagedDto, CreateDictDataDto, DictDataDto>, IDictDataAppService { private readonly IRepository<DictData, string> _repository; public DictDataAppService(IRepository<DictData, string> repository) : base(repository) { _repository = repository; } /// <summary> /// 自定义条件处理 /// </summary> /// <param name="input">查询条件Dto</param> /// <returns></returns> protected override IQueryable<DictData> CreateFilteredQuery(DictDataPagedDto input) { return base.CreateFilteredQuery(input) .WhereIf(!DictType_ID.IsNullOrWhiteSpace(), t => t.DictType_ID.Contains(input.DictType_ID)) .WhereIf(!Name.IsNullOrWhiteSpace(), t => t.Name.Contains(input.Name)) .WhereIf(!Value.IsNullOrWhiteSpace(), t => t.Value.Contains(input.Value)) .WhereIf(!Remark.IsNullOrWhiteSpace(), t => t.Remark.Contains(input.Remark)) .WhereIf(!Seq.IsNullOrWhiteSpace(), t => t.Seq.Contains(input.Seq)); } /// <summary> /// 自定义排序处理 /// </summary> /// <param name="query">可查询LINQ</param> /// <param name="input">查询条件Dto</param> /// <returns></returns> protected override IQueryable<DictData> ApplySorting(IQueryable<DictData> query, DictDataPagedDto input) { return base.ApplySorting(query, input); //示例代码 //先按字典类型排序,而后同一个字典类型下的再按Seq排序 //return base.ApplySorting(query, input).OrderBy(s=>s.DictType_ID).ThenBy(s => s.Seq); } }
ApiCaller分层的代码实现以下所示。
/// <summary> /// 通用字典明细项目信息的Web API调用处理 /// </summary> public class DictDataApiCaller : AsyncCrudApiCaller<DictDataDto, string, DictDataPagedDto, CreateDictDataDto, DictDataDto>, IDictDataAppService { /// <summary> /// 提供单件对象使用 /// </summary> public static DictDataApiCaller Instance { get { return Singleton<DictDataApiCaller>.Instance; } } /// <summary> /// 默认构造函数 /// </summary> public DictDataApiCaller() { this.DomainName = "DictData";//指定域对象名称,用于组装接口地址 } }
这些信息是根据数据库对应字段信息和关系信息进行批量生成,咱们能够在这基础上进行必定的调整,以及增长本身的业务接口,那么就很是方便了。
利用代码生成工具的数据库元数据,结合模板引擎NVelocity,咱们能够为咱们的项目框架代码快速生成提供了一个快速有效、统一标准的生成方式,大大提升了生产效率。