上一章说到2个工具,那么本次就使用这个工具来搭建PasteDocument
创建PasteDocument项目
新开一个VS2022
我们选择创建新项目
在检索栏中输入paste进行检索,看到如上图,选择他,然后下一步
输入项目名称PasteDocument,然后点击创建
等待VS工作后,会打开如下图
注意默认打开的时候的启动项目是有问题的,我们选择PasteDocument.HttpApi.Host项目为启动项目
上图有一个警告,npm的,我们不理他!
上面的项目就是使用PasteTemplate创建的项目了,可以看到子项目的层级和ABP非常像!!
其实他就是ABP框架!!!
在PasteDocument.HttpApi.Host的项目下方,我看到到wwwroot文件夹如下
可以看到整个这个就是当前项目的管理端页面,可以看到整个管理端的页面非常少,就几个html文件,注意看pasteform这个就是贴代码PasteForm的经典文件!
PasteForm的管理端是如上特点,那么对应的API呢?
如上图,首先一个是PasteDocument.Application.Contracts项目中有引入PasteFormHelper的包
然后是查看PasteDocument.Application项目中的UserInfoAppService接口为例,有以上标注的接口!
特别是
ReadAddModel
ReadUpdateModel
ReadListModel
这几个接口的作用就是读取对应的Dto的模型字段,备注和特性等,用于管理端UI的显示!
启动项目
以上是默认创建的内容,我们接下来启动下,看看这个用项目模板生成的项目,能否正常运行
按照上图的操作,由于项目是使用EF的,内置默认为sqlite数据库,配置可以见appsettings.json的配置
按照上图操作后,我这的显示是操作成功的,我们点击最上方的启动,运行看看
可以看到打印一大堆内容后,看到如上图的提示,我们按照提示打开这个2222看看
http://localhost:22222/page/index.html
打开后,跳转到登陆页面,按照默认的账号和密码,输入图形验证码后执行登陆
登陆成功后,可以看到如下图
这里可以看到系统有创建默认的权限和菜单,账号,角色等
项目的创建到这里就算完成了,那么接下来的就是我们如何在这个基础上搭建对应的需求表!
数据表需求
基于第一篇的需求,我大概罗列了如下需求
基于以上的分析,在PasteDocument.Domain中创建模块markmodels(其实就是一个文件夹)
然后创建如下内容
Company 表示组织
namespace PasteDocument.usermodels
{
/// <summary>
/// 组织信息
/// </summary>
public class CompanyInfo : Entity<int>
{
/// <summary>
/// 名称
/// </summary>
[MaxLength(32)]
public string Name { get; set; } = "";
/// <summary>
/// 图标
/// </summary>
[MaxLength(256)]
public string Head { get; set; } = "";
/// <summary>
/// 描述
/// </summary>
[MaxLength(256)]
public string Desc { get; set; } = "";
/// <summary>
/// 备注
/// </summary>
[MaxLength(32)]
public string Mark { get; set; } = "";
/// <summary>
/// 创建时间
/// </summary>
public DateTime CreateDate { get; set; } = DateTime.Now;
/// <summary>
/// 创建者
/// </summary>
public int UserId { get; set; }
}
}
ProjectInfo 表示项目信息
namespace PasteDocument.markmodels
{
/// <summary>
/// 项目信息 软件信息,示例商城
/// </summary>
[Index(nameof(Code), IsUnique = true)]
public class ProjectInfo : Entity<int>
{
/// <summary>
/// 代码 一般作为Route使用
/// </summary>
[MaxLength(32)]
public string Code { get; set; } = "";
/// <summary>
/// 名称 示例贴代码商城
/// </summary>
[MaxLength(32)]
public string Name { get; set; } = "";
/// <summary>
/// 说明 这个项目简介说明
/// </summary>
[MaxLength(128)]
public string Desc { get; set; } = "";
/// <summary>
/// 备注 内部备注
/// </summary>
[MaxLength(64)]
public string Mark { get; set; } = "";
/// <summary>
/// 创建者
/// </summary>
public int UserId { get; set; }
/// <summary>
/// 图标样式 示例Hui-iconfont-jifen
/// </summary>
[MaxLength(64)]
public string Icon { get; set; } = "";
/// <summary>
/// 图标 LOGO,一般是自定义上传
/// </summary>
[MaxLength(128)]
public string Head { get; set; } = "";
/// <summary>
/// 主页 项目主页
/// </summary>
[MaxLength(256)]
public string HomeUrl { get; set; } = "";
/// <summary>
/// 组织 率属于哪个组织
/// </summary>
public int CompanyId { get; set; }
/// <summary>
/// 创建时间
/// </summary>
public DateTime CreateDate { get; set; } = DateTime.Now;
/// <summary>
/// 排序
/// </summary>
public int Sort { get; set; }
/// <summary>
/// 状态
/// </summary>
public bool IsEnable { get; set; } = true;
/// <summary>
/// 公开
/// </summary>
public bool IsPublic { get; set; } = false;
}
}
ModuleInfo 表示模块信息
namespace PasteDocument.markmodels
{
/// <summary>
/// 模块信息 示例商品
/// </summary>
public class ModuleInfo : Entity<int>
{
/// <summary>
/// 项目
/// </summary>
public int ProjectId { get; set; }
/// <summary>
/// 代码 示例:product
/// </summary>
[MaxLength(32)]
public string Code { get; set; } = "";
/// <summary>
/// 名称 示例:商品信息
/// </summary>
[MaxLength(32)]
public string Name { get; set; } = "";
/// <summary>
/// 头像
/// </summary>
[MaxLength(128)]
public string Head { get; set; } = "";
/// <summary>
/// 图标 示例:Hui-iconfont-img2
/// </summary>
[MaxLength(64)]
public string Icon { get; set; } = "";
/// <summary>
/// 父级
/// </summary>
public int FatherId { get; set; }
/// <summary>
/// 父级簇
/// </summary>
[MaxLength(20)]
public string FatherStr { get; set; } = "";
/// <summary>
/// 层级
/// </summary>
public int Level { get; set; }
/// <summary>
/// 排序
/// </summary>
public int Sort { get; set; }
/// <summary>
/// 排序簇
/// </summary>
[MaxLength(20)]
public string SortStr { get; set; } = "";
/// <summary>
/// 创建者
/// </summary>
public int UserId { get; set; }
/// <summary>
/// 子项数
/// </summary>
public int Items { get; set; }
/// <summary>
/// 展开 默认是否展开下一级
/// </summary>
public bool IsOpen { get; set; } = true;
/// <summary>
/// 状态
/// </summary>
public bool IsEnable { get; set; } = true;
/// <summary>
/// 组织 率属于哪个组织
/// </summary>
public int CompanyId { get; set; }
}
}
FieldInfo 表示字段信息
namespace PasteDocument.markmodels
{
/// <summary>
/// 字段说明 示例:封面图
/// </summary>
public class FieldInfo : Entity<int>
{
/// <summary>
/// 项目
/// </summary>
public int ProjectId { get; set; }
/// <summary>
/// 模块
/// </summary>
public int ModuleId { get; set; }
/// <summary>
/// 代码 示例:code
/// </summary>
[MaxLength(32)]
public string Code { get; set; } = "";
/// <summary>
/// 名称 字段名称,示例:封面图
/// </summary>
[MaxLength(32)]
public string Name { get; set; } = "";
/// <summary>
/// 内容 html
/// </summary>
public string Context { get; set; } = "";
/// <summary>
/// 内容 Markdown
/// </summary>
public string MarkDown { get; set; } = "";
/// <summary>
/// 创建时间
/// </summary>
public DateTime CreateDate { get; set; } = DateTime.Now;
/// <summary>
/// 排序
/// </summary>
public int Sort { get; set; }
/// <summary>
/// 状态
/// </summary>
public bool IsEnable { get; set; } = true;
/// <summary>
/// 创建者
/// </summary>
public int UserId { get; set; }
/// <summary>
/// 回复数
/// </summary>
public int ReplyNum { get; set; }
/// <summary>
/// 点赞数
/// </summary>
public int LikeNum { get; set; }
/// <summary>
/// 编辑类型
/// </summary>
public EnumEditModel EditModel { get; set; }
/// <summary>
/// 更新时间
/// </summary>
public DateTime? UpdateDate { get; set; }
/// <summary>
/// 组织 率属于哪个组织
/// </summary>
public int CompanyId { get; set; }
}
}
查看以上的内容,可以看到对应的表的字段我是如何处理的,至于为啥不用外表模式?这个看个人习惯,要使用外表的模式也是可以的,不过我个人不习惯用!
以上是CodeFirst的第一步Code 那么接下来的,就是我们要为这些生成对应的Dto,AppService等 这个工作我交给代码生成器来处理,执行这些操作前,先查看下上方的代码 按照项目模板中的RoleInfoListDto为例
///<summary>
///权限列表
///</summary>
[PasteLinkQuery("fatherId")]
public class RoleInfoListDto
{
/// <summary>
/// ID
/// </summary>
[ColumnDataType("orderby", "Id", "Id desc")]
public int Id { get; set; }
///<summary>
///名称
///</summary>
[PasteClass]
[ColumnDataType("html", "<div class=\"level level{{:=item.level}} role{{:=item.roleTypeInt}}\">{{ if(item.icon){ }}<i class=\"Hui-iconfont {{:=item.icon}}\"></i>{{ } }} {{:=item.name}}</div>")]
public string Name { get; set; }
///<summary>
///模块
///</summary>
[PasteClass]
[PasteHidden]
public string Model { get; set; }
///<summary>
///权限
///</summary>
[PasteClass]
[PasteHidden]
public string Role { get; set; }
/// <summary>
/// 图标名称 一般表示样式名称
/// </summary>
[MaxLength(32)]
[PasteHidden]
public string Icon { get; set; }
/// <summary>
/// 路径/权限 作为菜单类型的路径
/// </summary>
[MaxLength(128)]
[PasteClass]
[ColumnDataType("html", "<div class=\"idesc\">{{:=item.path}}{{:=item.model}} {{:=item.role}}</div>")]
public string Path { get; set; }
/// <summary>
/// 权限类型 0权限1菜单2按钮,如何让前端支持这个显示
/// </summary>
[PasteSelect(PasteFormString.SelectRoleTypeQuery)]
public int RoleType { get; set; }
/// <summary>
/// 权限类型
/// </summary>
[PasteHidden]
public int RoleTypeInt { get { return RoleType; } }
///<summary>
///描述
///</summary>
[PasteClass]
public string Desc { get; set; }
///<summary>
///状态
///</summary>
[ColumnDataType("switch", "view")]
public bool IsEnable { get; set; }
/// <summary>
/// 绑定 扩展基于角色的时候是否拥有这个权限
/// </summary>
[ColumnDataType("switch")]
[ColumnDataType("hidden", "bind")]
public bool ExtendBind { get; set; }
///<summary>
///排序
///</summary>
[ColumnDataType("orderby", "Sort", "Sort desc")]
public int Sort { get; set; }
///<summary>
///父级
///</summary>
[ColumnDataType("outerdisplay", "", "extendFather?.name || ''")]
public int FatherId { get; set; }
/// <summary>
/// 父级信息,为了给上一个字段FatherId显示使用,你也可以把FatherId隐藏,只显示这个字段,或者2个都显示
/// </summary>
[ColumnDataType("hidden")]
public RoleShortModel ExtendFather { get; set; }
///<summary>
///层级
///</summary>
[ColumnDataType("orderby", "Level", "Level desc")]
public int Level { get; set; }
///<summary>
///排序串
///</summary>
[PasteHidden]
public string SortStr { get; set; }
/// <summary>
/// 添加子权限
/// </summary>
[ColumnDataType("menu", "添加子集", "open_window('添加子权限','./view.html?path=roleInfo&fatherId={{:=item.id}}');")]
public int Menu1 { get; set; }
/// <summary>
/// 详情
/// </summary>
[ColumnDataType("menu", "详情", "open_window('详细','./detail.html?path=roleInfo&id={{:=item.id}}');")]
public int Menu2 { get; set; }
/// <summary>
/// 查看子集
/// </summary>
[ColumnDataType("menu", "查看子集", "open_window('查看子集','./index.html?path=roleInfo&fatherId={{:=item.id}}');")]
public int Menu3 { get; set; }
}
可以看到针对不同的字段,我们需要给他配置不一样的特性,或者是不配置! 一个数据表对应至少4个Dto,所以我们需要改造下,让代码生成器支持自动帮我们补充对应的特性 这样可以减少手动输入的错误问题 打开PasteDocument.Domain/template/readme.md
# 在当前文件夹下可以创建对应的模板文件
index.html
view.html
add.html
edit.html
index.vue
view.vue
add.vue
edit.vue
# 模板写法资料
//http://dotliquidmarkup.org/
//https://shopify.github.io/liquid/tags/template/
//两个单词的时候应该改成小写中间加_ 比如DirName 应为 dir_name
大概意思就是这个文件夹存放的是配置和模板文件,你不喜欢的话可以根据规则自己创建模板文件,不过模板文件的文件名有哟要求,这里我已经习惯默认模板了,就不搞这个了 重命名config.json.txt为config.json然后打开他
{
"readme": "用使用下面的规则请重命名文件为config.json",
"ignore": { //表示Dto中不生成这些字段,比如CreateDate那个一般是创建的时候生成的不需要AddDto传递过来
"all": {
"add": [ "CreateDate", "AdminUid", "CreateUid" ],
"update": [ "UpdateDate", "CreateDate" ],
"detail": [ "UpdateDate", "CreateDate" ],
"list": [ "Body","Content","Context" ]
},
"other": {
"NewTable:add": ["CreateDate"] //表示指定某一个表的某一个模式下
}
},
"attribute": {
"ignore": [ "Comment", "Display", "Decription", "Index", "DefaultValue", "Column", "NotMapped", "ConcurrencyStamp" ], //表示忽略哪些来自Domain的属性
"all": {
"UserId": "[ColumnDataType(\"outer\",\"userInfo\",\"extendUser\",\"id\",\"userName\")]", //表示这个字段UserId需要添加这个过滤器多个之间用::隔开 示例:[PasteLeft]::[PasteHidden]
"GradeId": "[ColumnDataType(\"outer\",\"gradeInfo\",\"extendGrade\",\"id\",\"name\")]"
},
"other": {
"NewTable:add:Head":"[PasteImage(1,\"head\")]::[PasteHidden]",//多个之间使用::隔开,表示在不同的Dto中为字段添加属性
"NewTable:list:Desc": "[PasteLeft]"
}
}
}
看上面的解释,意思就是针对Dto的特性和字段的配置信息,所以我们针对当前项目做一个调整,调整后如下:
{
"readme": "用使用下面的规则请重命名文件为config.json",
"ignore": { //表示Dto中不生成这些字段,比如CreateDate那个一般是创建的时候生成的不需要AddDto传递过来
"all": {
"add": [ "CreateDate", "AdminUid", "CreateUid","UserId","CompanyId" ],
"update": [ "UpdateDate", "CreateDate","UserId","CompanyId" ],
"detail": [ "UpdateDate", "CreateDate" ],
"list": [ "Body" ]
},
"other": {
"NewTable:add": ["CreateDate"] //表示指定某一个表的某一个模式下
}
},
"attribute": {
"ignore": [ "Comment", "Display", "Decription", "Index", "DefaultValue", "Column", "NotMapped", "ConcurrencyStamp" ], //表示忽略哪些来自Domain的属性
"all": {
"UserId": "[ColumnDataType(\"outer\",\"userInfo\",\"extendUser\",\"id\",\"userName\")]", //表示这个字段UserId需要添加这个过滤器多个之间用::隔开 示例:[PasteLeft]::[PasteHidden]
"GradeId": "[ColumnDataType(\"outer\",\"gradeInfo\",\"extendGrade\",\"id\",\"name\")]",
"CompanyId": "[PasteOuter(\"companyInfo\",\"extendCompany\",\"id\",\"name\")]",
"ProjectId": "[PasteOuter(\"projectInfo\",\"extendProject\",\"id\",\"name\")]",
"ModuleId": "[PasteOuter(\"moduleInfo\",\"extendModule\",\"id\",\"name\")]",
"FieldId": "[PasteOuter(\"fieldInfo\",\"extendField\",\"id\",\"name\")]",
"Head": "[PasteImage(1,\"head\",\"60*60\")]"
},
"other": {
"NewTable:add:Head":"[PasteImage(1,\"head\")]::[PasteHidden]",//多个之间使用::隔开,表示在不同的Dto中为字段添加属性
"NewTable:list:Desc": "[PasteLeft]"
}
}
}
关键是一下要点
因为在当前系统中的UserId,CompanyId都是由接口赋值的,获取当前登陆者的信息赋值给新加信息,所以不需要外部输入
以上步骤完成后,我们就可以执行代码生成了
生成代码
如上图,选定对应的这几个文件,注意Enum枚举的不要忘了,然后按照上图操作,点击完整生成!
点击后,等待执行完成,系统会弹出一个小窗告知生成成功!
生成成功后,我们可以在
PasteDocument.Application
PasteDocument.Application.Contracts
都生成了新的文件夹markmoduls
而且里面都有对应的文件
先处理下EF中的新的内容写入后的命名引入的问题
然后是PasteDocument.Application.Contracts的有枚举的Dto的命名引入问题
还有一个是 PasteDocument.Application/PasteDocumentApplicationAutoMapperProfile.cs 这几个页面处理命名空间的引入问题后,尝试代码重新生成,按照提示操作
生成预期
我们看看生成的Dto(PasteDocument.Application.Contracts/markmodels/ProjectInfoDto.cs)是否符合预期
using Volo.Abp.Application.Dtos;
using System;
using System.Collections.Generic;
using System.Text;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using Volo.Abp.Domain.Entities;
using PasteFormHelper;
using PasteDocument.Application.Contracts;
namespace PasteDocument.markmodels
{
///<summary>
///项目信息 软件信息,示例商城
///</summary>
public class ProjectInfoAddDto
{
///<summary>
///代码 一般作为Route使用
///</summary>
[MaxLength(32)]
public string Code { get; set; }
///<summary>
///名称 示例贴代码商城
///</summary>
[MaxLength(32)]
public string Name { get; set; }
///<summary>
///说明 这个项目简介说明
///</summary>
[MaxLength(128)]
public string Desc { get; set; }
///<summary>
///备注 内部备注
///</summary>
[MaxLength(64)]
public string Mark { get; set; }
///<summary>
///图标样式 示例Hui-iconfont-jifen
///</summary>
[MaxLength(64)]
public string Icon { get; set; }
///<summary>
///图标 LOGO,一般是自定义上传
///</summary>
[MaxLength(128)]
[PasteImage(1,"head","60*60")]
public string Head { get; set; }
///<summary>
///主页 项目主页
///</summary>
[MaxLength(256)]
public string HomeUrl { get; set; }
///<summary>
///排序
///</summary>
public int Sort { get; set; }
///<summary>
///状态
///</summary>
public bool IsEnable { get; set; }
///<summary>
///公开
///</summary>
public bool IsPublic { get; set; }
}
///<summary>
///项目信息 软件信息,示例商城
///</summary>
public class ProjectInfoUpdateDto:EntityDto<int>
{
///<summary>
///代码 一般作为Route使用
///</summary>
[MaxLength(32)]
public string Code { get; set; }
///<summary>
///名称 示例贴代码商城
///</summary>
[MaxLength(32)]
public string Name { get; set; }
///<summary>
///说明 这个项目简介说明
///</summary>
[MaxLength(128)]
public string Desc { get; set; }
///<summary>
///备注 内部备注
///</summary>
[MaxLength(64)]
public string Mark { get; set; }
///<summary>
///图标样式 示例Hui-iconfont-jifen
///</summary>
[MaxLength(64)]
public string Icon { get; set; }
///<summary>
///图标 LOGO,一般是自定义上传
///</summary>
[MaxLength(128)]
[PasteImage(1,"head","60*60")]
public string Head { get; set; }
///<summary>
///主页 项目主页
///</summary>
[MaxLength(256)]
public string HomeUrl { get; set; }
///<summary>
///排序
///</summary>
public int Sort { get; set; }
///<summary>
///状态
///</summary>
public bool IsEnable { get; set; }
///<summary>
///公开
///</summary>
public bool IsPublic { get; set; }
}
///<summary>
///项目信息 软件信息,示例商城
///</summary>
public class ProjectInfoDto:EntityDto<int>
{
///<summary>
///代码 一般作为Route使用
///</summary>
[MaxLength(32)]
public string Code { get; set; }
///<summary>
///名称 示例贴代码商城
///</summary>
[MaxLength(32)]
public string Name { get; set; }
///<summary>
///说明 这个项目简介说明
///</summary>
[MaxLength(128)]
public string Desc { get; set; }
///<summary>
///备注 内部备注
///</summary>
[MaxLength(64)]
public string Mark { get; set; }
///<summary>
///创建者
///</summary>
[ColumnDataType("outer","userInfo","extendUser","id","userName")]
public int UserId { get; set; }
///<summary>
///图标样式 示例Hui-iconfont-jifen
///</summary>
[MaxLength(64)]
public string Icon { get; set; }
///<summary>
///图标 LOGO,一般是自定义上传
///</summary>
[MaxLength(128)]
[PasteImage(1,"head","60*60")]
public string Head { get; set; }
///<summary>
///主页 项目主页
///</summary>
[MaxLength(256)]
public string HomeUrl { get; set; }
///<summary>
///组织 率属于哪个组织
///</summary>
[PasteOuter("companyInfo","extendCompany","id","name")]
public int CompanyId { get; set; }
///<summary>
///排序
///</summary>
public int Sort { get; set; }
///<summary>
///状态
///</summary>
public bool IsEnable { get; set; }
///<summary>
///公开
///</summary>
public bool IsPublic { get; set; }
}
///<summary>
///项目信息 软件信息,示例商城
///</summary>
public class ProjectInfoListDto:EntityDto<int>
{
///<summary>
///代码 一般作为Route使用
///</summary>
[MaxLength(32)]
public string Code { get; set; }
///<summary>
///名称 示例贴代码商城
///</summary>
[MaxLength(32)]
public string Name { get; set; }
///<summary>
///说明 这个项目简介说明
///</summary>
[MaxLength(128)]
public string Desc { get; set; }
///<summary>
///备注 内部备注
///</summary>
[MaxLength(64)]
public string Mark { get; set; }
///<summary>
///创建者
///</summary>
[ColumnDataType("outer","userInfo","extendUser","id","userName")]
public int UserId { get; set; }
///<summary>
///图标样式 示例Hui-iconfont-jifen
///</summary>
[MaxLength(64)]
public string Icon { get; set; }
///<summary>
///图标 LOGO,一般是自定义上传
///</summary>
[MaxLength(128)]
[PasteImage(1,"head","60*60")]
public string Head { get; set; }
///<summary>
///主页 项目主页
///</summary>
[MaxLength(256)]
public string HomeUrl { get; set; }
///<summary>
///组织 率属于哪个组织
///</summary>
[PasteOuter("companyInfo","extendCompany","id","name")]
public int CompanyId { get; set; }
///<summary>
///创建时间
///</summary>
public DateTime CreateDate { get; set; }
///<summary>
///排序
///</summary>
public int Sort { get; set; }
///<summary>
///状态
///</summary>
public bool IsEnable { get; set; }
///<summary>
///公开
///</summary>
public bool IsPublic { get; set; }
}
///<summary>
/// 查询
///</summary>
public class InputQueryProjectInfo:InputSearchBase{
}
}
我的习惯是把一个数据表的所有Dto放一个文件,这样好找内容,不至于文件非常多!从上面可以看到在AddDto中是没有我们配置的UserId,CompanyId等字段的,符合预期!!!
再看看生成的ProjectInfoAppService.cs
using System.Collections.Generic;
using System;
using System.Linq;
using System.Linq.Dynamic.Core;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using Volo.Abp;
using Volo.Abp.Application.Dtos;
using Volo.Abp.Domain.Repositories;
using PasteFormHelper;
using PasteDocument.Application.Contracts;
namespace PasteDocument.markmodels
{
/// <summary>
///
///</summary>
[TypeFilter(typeof(RoleAttribute), Arguments = new object[] { "data", "view" })]
public class ProjectInfoAppService : PasteDocumentAppService
{
/// <summary>
///
///</summary>
public ProjectInfoAppService():base()
{
}
/// <summary>
/// 读取AddDto的数据模型
/// </summary>
/// <returns></returns>
[HttpGet]
[TypeFilter(typeof(RoleAttribute), Arguments = new object[] { "data", "add" })]
public PasteBuilderHelper.VoloModelInfo ReadAddModel()
{
var _model = PasteBuilderHelper.ReadModelProperty<ProjectInfoAddDto>(new ProjectInfoAddDto());
return _model;
}
/// <summary>
/// 读取UpdateDto的数据模型
/// </summary>
/// <returns></returns>
[HttpGet]
[TypeFilter(typeof(RoleAttribute), Arguments = new object[] { "data", "edit" })]
public async Task<PasteBuilderHelper.VoloModelInfo> ReadUpdateModel(int id)
{
var _info = await _dbContext.ProjectInfo.Where(x => x.Id == id).AsNoTracking().FirstOrDefaultAsync();
if (_info == null || _info == default)
{
throw new PasteCodeException("查询的信息不存在,无法执行编辑操作!");
}
var dto = ObjectMapper.Map<ProjectInfo, ProjectInfoUpdateDto>(_info);
var _dataModel = PasteBuilderHelper.ReadModelProperty<ProjectInfoUpdateDto>(dto);
return _dataModel;
}
/// <summary>
/// 读取Dto的数据模型 用于查看详情
/// </summary>
/// <returns></returns>
[HttpGet]
[TypeFilter(typeof(RoleAttribute), Arguments = new object[] { "data", "edit" })]
public async Task<PasteBuilderHelper.VoloModelInfo> ReadDetailModel(int id)
{
var _info = await _dbContext.ProjectInfo.Where(x => x.Id == id).AsNoTracking().FirstOrDefaultAsync();
if (_info == null || _info == default)
{
throw new PasteCodeException("查询的信息不存在,无法执行编辑操作!");
}
var dto = ObjectMapper.Map<ProjectInfo, ProjectInfoDto>(_info);
var _dataModel = PasteBuilderHelper.ReadModelProperty<ProjectInfoDto>(dto);
return _dataModel;
}
/// <summary>
/// 读取ListDto的数据模型
/// </summary>
/// <returns></returns>
[HttpGet]
public PasteBuilderHelper.VoloModelInfo ReadListModel()
{
var _model = PasteBuilderHelper.ReadModelProperty<ProjectInfoListDto>(new ProjectInfoListDto());
var _query_model = PasteBuilderHelper.ReadModelProperty(new InputQueryProjectInfo());
if (_query_model != null)
{
_model.QueryProperties = _query_model.Properties;
}
return _model;
}
/// <summary>
/// 获取
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
[HttpGet]
public async Task<PagedResultDto<ProjectInfoListDto>> Page([FromQuery] InputQueryProjectInfo input)
{
var _query = _dbContext.ProjectInfo.Where(t => 1 == 1);
var _pagedto = new PagedResultDto<ProjectInfoListDto>();
if (input.page == 1)
{
_pagedto.TotalCount = await _query.CountAsync();
}
var dataList = await _query
.OrderByDescending(x => x.Id)
.Page(input.page, input.size)
.AsNoTracking()
.ToListAsync();
if(dataList==null||dataList.Count == 0){
throw new PasteCodeException("没有查询到数据",204);
}
var temList = ObjectMapper.Map<List<ProjectInfo>, List<ProjectInfoListDto>>(dataList);
_pagedto.Items = temList;
return _pagedto;
}
/// <summary>
/// 添加一个
///</summary>
/// <param name="input"></param>
/// <returns></returns>
[HttpPost]
[TypeFilter(typeof(RoleAttribute), Arguments = new object[] { "data", "add" })]
public async Task<ProjectInfoDto> CreateItemAsync(ProjectInfoAddDto input)
{
var _userid = base.ReadCurrentAdminId();
var newu = ObjectMapper.Map<ProjectInfoAddDto, ProjectInfo>(input);
//添加自定义
_dbContext.Add(newu);
await _dbContext.SaveChangesAsync();
var backinfo = ObjectMapper.Map<ProjectInfo, ProjectInfoDto>(newu);
return backinfo;
}
/// <summary>
/// 更新一个
///</summary>
/// <param name="input"></param>
/// <returns></returns>
[HttpPost]
public async Task<ProjectInfoDto> UpdateItemAsync(ProjectInfoUpdateDto input)
{
var info = await _dbContext.ProjectInfo.Where(x => x.Id == input.Id).FirstOrDefaultAsync();
if (info == null || info == default)
{
throw new PasteCodeException("需要查询的信息不存在", 404);
}
ObjectMapper.Map<ProjectInfoUpdateDto, ProjectInfo>(input, info);
await _dbContext.SaveChangesAsync();
var backinfo = ObjectMapper.Map<ProjectInfo, ProjectInfoDto>(info);
return backinfo;
}
/// <summary>
/// 更新状态,或者更新绑定
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
/// <exception cref="PasteCodeException"></exception>
[HttpPost]
[TypeFilter(typeof(RoleAttribute), Arguments = new object[] { "data", "state" })]
public async Task<string> UpdateState(InputQueryUpdateState input)
{
if (!int.TryParse(input.id, out var _id))
{
throw new PasteCodeException("提供的参数id错误,无法继续执行");
}
//因为只有一个isenable,直接写
var find = await _dbContext.ProjectInfo.Where(x => x.Id == _id).FirstOrDefaultAsync();
if (find == null || find == default)
{
throw new PasteCodeException("没有找到对应的操作对象,无法继续执行");
}
//需要自行实现
return "暂未实现";
}
/// <summary>
/// 删除数据,不需要删除的话注意注释这个 ListDto中附带disable标注忽略删除
/// </summary>
/// <param name="id"></param>
/// <returns></returns>
[HttpPost]
[TypeFilter(typeof(RoleAttribute), Arguments = new object[] { "data", "del" })]
public async Task<string> Remove(int id)
{
var info = await _dbContext.ProjectInfo.Where(x => x.Id == id).FirstOrDefaultAsync();
if (info == null || info == default)
{
throw new PasteCodeException("需要查询的信息不存在", 404);
}
_dbContext.Remove(info);
await _dbContext.SaveChangesAsync();
return "删除成功";
}
}
}
生成成功后
执行Migration的部分
名字自己取,意思是生成哪个的变动等
然后我们启动项目后,去添加几个新的菜单
刷新后,就能在左侧的菜单中看到新的菜单项目了,你可以按照要求新增一个项目试试
至此,一个完整的CRUD就算搭建完成了
从整个项目来说,这个工作目前完成的量可能还不足1%
接下来我们将对这个项目进一步进行改造,让他符合我们的项目需求
我们下期见