博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Abp 代码生成器使用说明
阅读量:3532 次
发布时间:2019-05-20

本文共 9300 字,大约阅读时间需要 31 分钟。

Abp 代码生成器使用说明

介绍

在使用abp框架进行项目开发的时候,开始使用的是52abp的代码生成器,但是在使用的过程中,总有一些地方感觉不舒服,也许是出于程序员的强迫症吧。最终,我决定自己写一个简单的代码生成器使用。所以,也就有了这么一篇文章。

概述

我们先看看界面

在这里插入图片描述

只有这一个界面,因为只是为了生成后台的代码。从图中可以看出,我只是生成了领域服务层EntityFrameworkCore层应用层的相关代码,权限部分可以选择生成,也可用后期用到在生成。这里需要编辑的内容有:

1、实体类主键的类型,如Guidlong等;

2、实体类的中文名称,可在生成类的注释中使用,否则使用类名称;

3、选择在EditListDTO中显示的字段,勾选则生成此字段;

4、字段中文名称,实体类中默认有的会带出来,必填也是如此;

5、如果实体类中有定义字段长度,此处会自动带出,可在此修改,为 0 则不会在DTO中生成。

具体使用方式

创建一个实体类

我们以BaseCode为例子来说明。

首先,我们在领域层新建一个BaseCode文件夹,然后在此文件夹下创建BaseCode.cs类。在此类中添加相应的属性信息,具体代码如下:

public class BaseCode :Entity
,IPassivable{
[Required] [StringLength(maximumLength:50, ErrorMessage = "编码不能超过50字符")] [DisplayName("编码")] public string Code {
get; set; } [Required] [StringLength(50,MinimumLength = 10,ErrorMessage ="编码名称不能超过50字符")] [DisplayName("编码名称")] public string CodeName {
get; set; } [StringLength(200)] [DisplayName("描述")] public string Desc {
get; set; } [Required] [DisplayName("是否激活")] public bool IsActive {
get ; set; }}

关于实体类的具体定义规则,可参考。

此示例代码中添加RequiredStringLength特性,主要是为了测试界面数据的绑定,其实此处可用不定义,而是放在生成的配置类中定义。

但是对于DisplayName特性,我建议您定义,因为它不仅仅是在界面上绑定显示,可用在DTO中生成相应的注释;同样的,它还会生成相应的数据表字段说明。所以此处强烈建议您给出此字段的说明。

EF层生成的配置类

让我们来看看生成的代码:

/// /// 基础编码 EF配置,可完成必填,注释等内容的处理/// public class BaseCodeCfg : IEntityTypeConfiguration
{
///
/// 具体配置方法 /// ///
public void Configure(EntityTypeBuilder
builder) {
// ABP 为数据库中架构名称,可自行修改,sql server 的默认架构是dbo builder.ToTable("BaseCode", "ABP").HasComment("基础编码的相关信息") ; builder.Property(x => x.Id).HasComment(AbpConsts.CommentPrimaryKeyGuid); builder.Property(x => x.Code).HasComment("编码"); builder.Property(x => x.CodeName).HasComment("编码名称"); builder.Property(x => x.Desc).HasComment("描述"); builder.Property(x => x.IsActive).HasComment("是否激活"); }}

其实个人更加的建议,将RequiredStringLength等特性的定义放在此处,同样可在此处定义很多其他的约束,比如默认值等。

注意:生成的代码中的AbpConsts类是在领域层中生成的。

生成的项目结构如图:

在这里插入图片描述
为了使用生成配置类,我们需要在xxDbContext类中添加相关内容,此类可用在EF层的EntityFrameworkCore文件夹下找到。

添加的内容主要是两块,一个是实体类数据集属性,另一个是重写OnModelCreating方法。代码分别如下:

/* Define a DbSet for each entity of the application */public DbSet
BaseCodes;
protected override void OnModelCreating(ModelBuilder modelBuilder){
modelBuilder.ApplyConfiguration
(new BaseCodeCfg()); base.OnModelCreating(modelBuilder);}

这样在生成数据库时,相应的表字段注释也会随之生成。具体生成方式,可参考代码生成器中生成的readme.md说明文档。

让我们看下生成的数据库效果:

在这里插入图片描述

领域层(XX.Core)生成的类

在创建好的实体类上右击,在弹出的菜单中选择【Abp 代码生成器】后即可看到本文开头展示的界面。生成此层的相关代码,必须勾选【领域服务】复选框。

生成后,会在实体类的同层创建一个DomainService文件夹,并在其下生成领域服务接口和领域服务实现类。在领域层的根目录下生成一个AbpConsts.cs类和XXXDomainServiceBase.cs类。最后要说的是,还会在此层的根目录下生成一个Readme.md的说明文档。

这里简单展示下XXXDomainServiceBase.cs类的代码:

/// /// 自定义的基础领域服务,继承自abp框架的领域服务/// public abstract class DemoDomainServiceBase : DomainService{
/// /// 构造函数 /// protected DemoDomainServiceBase() {
LocalizationSourceName = DemoConsts.LocalizationSourceName; } /* Add your common members for all your domain services. */ /*在领域服务中添加你的自定义公共方法*/ }

项目结构可参考权限部分给的图片

应用层(XX.Application)生成的类

相对来说,这一层中生成的类最多。

首先我们来看看在应用层根目录下生成的XXXCrudAppServiceBase.cs类。其生成的代码如下:

/// /// 应用层增删改查的基类,自定义的业务类都可从此类继承/// public abstract class DemoCrudAppServiceBase
: AsyncCrudAppService
> where TEntity : class, IEntity
where TEntityDto : IEntityDto
where TUpdateInput : IEntityDto
{
///
/// 租户管理 /// public TenantManager TenantManager {
get; set; } ///
/// 用户管理 /// public UserManager UserManager {
get; set; } ///
/// 构造函数 /// public DemoCrudAppServiceBase(IRepository
repository) : base(repository) { LocalizationSourceName = DemoConsts.LocalizationSourceName; } ///
/// 得到当前用户信息 /// ///
protected virtual async Task
GetCurrentUserAsync() { var user = await UserManager.FindByIdAsync(AbpSession.GetUserId().ToString()); if (user == null) { throw new Exception("There is no current user!"); } return user; } ///
/// 得到当前租户信息 /// ///
protected virtual Task
GetCurrentTenantAsync() { return TenantManager.GetByIdAsync(AbpSession.GetTenantId()); } ///
/// 检查错误 /// ///
protected virtual void CheckErrors(IdentityResult identityResult) { identityResult.CheckErrors(LocalizationManager); }}

因为应用层的代码我主要是参考Abp框架的源码来处理的,而 AsyncCrudAppService<TEntity, TEntityDto, TPrimaryKey, TGetAllInput, TCreateInput, TUpdateInput, EntityDto<TPrimaryKey>>是在其源码中定义好的,可以直接使用的,所以才有了这个公共父类的实现。具体可查看。

其次,在应用层的根目录下创建一个Dtos文件夹,其下放了三个处理分页相关功能的类。

最主要的是应用服务相关的类,其文件结构和实体类建立时的文件结构相同,具体可参见下图:

在这里插入图片描述
如图,代码分三块:领域服务接口和其实现类,AutoMapper的映射配置类,还有就是具体的Dto类。这里的Dto类只是最基本的添加、编辑和列表及分页的类,可根据业务情况自行添加新的Dto类。

1、AutoMapper配置类的代码如下:

/// /// automapper配置类/// public class BaseCodeMapProfile : Profile{
/// /// 构造函数 /// public BaseCodeMapProfile() {
CreateMap
(); CreateMap
(); CreateMap
(); CreateMap
(); CreateMap
(); CreateMap
(); }}

定义的配置类直接继承了Profile类,这样只需要维护这个类中的映射关系,而不需要做其他的改动即可。这是因为在XXXApplicationModule.cs中定义了如下内容,自动完成了配置类的注入。

public override void Initialize(){
var thisAssembly = typeof(DemoApplicationModule).GetAssembly(); IocManager.RegisterAssemblyByConvention(thisAssembly); Configuration.Modules.AbpAutoMapper().Configurators.Add( // Scan the assembly for classes which inherit from AutoMapper.Profile cfg => cfg.AddMaps(thisAssembly) );}

2、关于Dtos中的类,我们以XXXEditDto类为例看看,代码如下:

/// /// BaseCode.BaseCode 的编辑DTO/// 
///
public class BaseCodeEditDto : EntityDto
{
///
/// 编码 /// [Required] [StringLength(50,ErrorMessage = "编码最大长度为50,最小长度为5",MinimumLength = 5)] public string Code {
get; set; } ///
/// 编码名称 /// [Required] [StringLength(50,ErrorMessage = "编码名称最大长度为50,最小长度为5",MinimumLength = 5)] public string BaseName {
get; set; } ///
/// 备注 /// [StringLength(200,ErrorMessage = "备注最大长度200")] public string Remark {
get; set; } ///
/// 是否激活 /// [Required] public bool IsActive {
get; set; } }

从此代码中可以看出,配置界面中的关于EditDto的相关配置内容都在此有所体现。

3、而对于应用服务类的生成,其接口类如下:

/// /// 应用层服务的接口方法///public interface IBaseCodeAppService : IAsyncCrudAppService
{
}

可以看到,其继承了Abp框架中定义的IAsyncCrudAppService接口,此接口中定义好了关于增删改查的相关方法,可以直接重写即可。生成的实现类代码如下:

/// /// 应用层服务的接口实现方法///[AbpAuthorize]public class BaseCodeAppService : DemoCrudAppServiceBase
,IBaseCodeAppService{
private readonly IBaseCodeManager _baseCodeManager; ///
/// 构造函数 /// public BaseCodeAppService(IRepository
baseCodeRepository, IBaseCodeManager baseCodeManager) : base(baseCodeRepository) {
_baseCodeManager = baseCodeManager; } ///
/// 添加基础编码 /// ///
///
public override async Task
CreateAsync(CreateBaseCodeInputDto input) {
var entity = ObjectMapper.Map
(input); await _baseCodeManager.CreateAsync(entity); return MapToEntityDto(entity); } ///
/// 修改基础编码 /// ///
///
public override async Task
UpdateAsync(BaseCodeEditDto input) {
var entity = await this._baseCodeManager.FindByIdAsync(input.Id); ObjectMapper.Map(input, entity); return MapToEntityDto(entity); } ///
/// 删除基础编码 /// ///
///
public override async Task DeleteAsync(EntityDto
input) { await this._baseCodeManager.DeleteAsync(input.Id); } ///
/// 得到所有的基础编码 /// ///
///
public override Task
> GetAllAsync(PagedBaseCodeResultRequestDto input) { return base.GetAllAsync(input); } ///
/// 根据id得到指定的病区信息 /// ///
///
public override Task
GetAsync(EntityDto
input) { return base.GetAsync(input); } ///
/// 创建过滤条件的自定义,在获取列表信息中使用 /// ///
///
protected override IQueryable
CreateFilteredQuery(PagedBaseCodeResultRequestDto input) { return Repository.GetAll().WhereIf(!input.Keyword.IsNullOrWhiteSpace(), x => x.Code.Contains(input.Keyword) || x.BaseName.Contains(input.Keyword) || x.Remark.Contains(input.Keyword)); } ///
/// 重写排序规则 /// ///
///
///
protected override IQueryable
ApplyPaging(IQueryable
query, PagedBaseCodeResultRequestDto input) { return base.ApplyPaging(query, input); }}

权限相关的类

权限相关的类也是在领域层生成的,在实体类同层创建一个Authorization文件夹,和领域服务的文件夹也是同层的。在此文件夹下有两个类,分别是XXXAuthorizationProvider.cs类和XXXPermissions.cs类。

还有一个类放在领域层根目录的Authorization文件夹下,这个文件夹及下面的相关类是Abp框架生成的,我们只是在下面添加一个AbpPermissions.cs类。

生成的项目结构如下:

在这里插入图片描述
这里简单展示下AbpPermissions.cs类的代码:

/// /// 项目定义的默认权限变量名称/// public class AbpPermissions{
public const string Pages = "Pages"; public const string Pages_Administration = "Pages.Administration"; // 可自定义新的权限}

总结

此代码生成器只是实现了最基本的代码实现,对于前端和单元测试等都没有实现。对于一些细节,如“是否第一次生成”这样的,也没有进行处理。个人考虑是,因为代码中对于文件夹、文件的生成都有判断,有则不在生成,没有才会生成。在不进行模板翻译而只是判断有无的情况下,速度很快,所以没有考虑进行界面的配置。

对于项目名称结构,也只是测试了形如xxx.xxx.Core的项目,对于xxx.Core形式的命名项目没有进行测试。关于实体类层级,我只测试了一层和两层的情况,即folder/entity.cs的形式和folder1/folder2/entity.cs的形式。

我已将源代码放在上,可自行获取代码进行查看。可在bin/debug文件夹下AbpGenerateProject.vsix文件并点击安装,安装好后就可以在vs2019中使用了。如果有改进的想法的可以自行实现或者留言讨论。

转载地址:http://ibwhj.baihongyu.com/

你可能感兴趣的文章