PasteForm框架开发之Entity多级嵌套的表单的实现

你相信么,使用PasteForm框架开发,管理端居然不要写代码!!!
一起来看看PasteForm是否支持多级表模式(外表)

需求假设

假如有这么一个需求,就是订单表,包含了多级的信息,比如这个订单包含了哪些商品,又有哪些货品信息等,以下是一个概览,模拟的是实际的一些层级关系

Entity定义

using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using Volo.Abp.Domain.Entities;namespace LevelEntity.levelmodels
{/// <summary>/// /// </summary>public class OrderDetail : Entity<int>{/// <summary>/// 标题/// </summary>[MaxLength(128)]public string Title { get; set; }/// <summary>/// 封面图/// </summary>[MaxLength(128)]public string CoverImage { get; set; }/// <summary>/// 订单包含产品/// </summary>public ICollection<OrderProduct> Products { get; set; }/// <summary>/// 订单金额/// </summary>public OrderPrice Price { get; set; }}/// <summary>/// /// </summary>public class OrderProduct : Entity<int>{/// <summary>/// /// </summary>public int ProductId { get; set; }/// <summary>/// /// </summary>public int BuyNum { get; set; }/// <summary>/// /// </summary>public int ProductPrice { get; set; }/// <summary>/// 货品信息/// </summary>public SkuInfo Sku { get; set; }}/// <summary>/// /// </summary>public class SkuInfo : Entity<int>{/// <summary>/// 货品名称/// </summary>[MaxLength(32)]public string SkuName { get; set; }}/// <summary>/// /// </summary>public class OrderPrice : Entity<int>{/// <summary>/// 订单总金额/// </summary>public int TotalAmount { get; set; }/// <summary>/// 优惠总金额/// </summary>public int FreeAmount { get; set; }}/// <summary>/// 购买者信息/// </summary>public class OrderBuyer : Entity<int>{/// <summary>/// 姓名/// </summary>[MaxLength(16)]public string Name { get; set; }/// <summary>/// 年龄/// </summary>public int Age { get; set; }}
}

如上所示,我把他们全部放于XXX.Domain/levelmodels的文件夹的OrderDetail.cs中
结构如下
在这里插入图片描述

确认了字段的注释等之后,右键OrderDetail.cs这个文件,使用PasteBuidler构建代码
可以生成对应的Dto和AppService模块
在这里插入图片描述

如上图所示,会在这些地方生成对应的代码,自动生成的代码有些需要调整,我们进行针对性的调整下

调整Dto

我们以新增OrderDetail为例子,对OrderDetailAddDto调整如下

using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using LevelEntity.Application.Contracts;
using PasteFormHelper;namespace LevelEntity.levelmodels
{///<summary>//////</summary>public class OrderDetailAddDto{///<summary>///标题///</summary>[MaxLength(128)]public string Title { get; set; }///<summary>///封面图///</summary>[MaxLength(128)]public string CoverImage { get; set; }///<summary>///包含产品 这里会自动构建组,因为是list和directsun///</summary>[PasteDirectsun]public List<OrderProductUpdateDto> Products { get; set; }///<summary>///订单金额///</summary>[PasteDirectsun]public OrderPriceUpdateDto Price { get; set; }}///<summary>//////</summary>public class OrderDetailUpdateDto : OrderDetailAddDto{/// <summary>/// /// </summary>public int Id { get; set; }/<summary>/标题/</summary>//[MaxLength(128)]//public string Title { get; set; }/<summary>/封面图/</summary>//[MaxLength(128)]//public string CoverImage { get; set; }/<summary>/订单包含产品/</summary>//public List<OrderProductDto> Products { get; set; }/<summary>/订单金额/</summary>//public OrderPriceDto Price { get; set; }}///<summary>//////</summary>public class OrderDetailDto : OrderDetailUpdateDto{/<summary>/标题/</summary>//[MaxLength(128)]//public string Title { get; set; }/<summary>/封面图/</summary>//[MaxLength(128)]//public string CoverImage { get; set; }/<summary>/订单包含产品/</summary>//public List<OrderProductDto> Products { get; set; }/<summary>/订单金额/</summary>//public OrderPriceDto Price { get; set; }}///<summary>//////</summary>public class OrderDetailListDto{/// <summary>/// ID/// </summary>public int Id { get; set; }///<summary>///标题///</summary>[MaxLength(128)][PasteClass]public string Title { get; set; }///<summary>///封面图///</summary>[MaxLength(128)][PasteClass]public string CoverImage { get; set; }///<summary>///订单包含产品///</summary>[PasteHidden]public List<OrderProductDto> Products { get; set; }///<summary>///订单金额///</summary>[PasteDisplay("totalAmount")][PasteFenToYuan]public OrderPriceDto Price { get; set; }}///<summary>/// 查询///</summary>public class InputQueryOrderDetail : InputSearchBase{/// <summary>/// 货品名称/// </summary>public string sku_name { get; set; }/// <summary>/// 商品ID/// </summary>public int pro_id { get; set; }}
}

注意看OrderDetailAddDto的这个信息

        ///<summary>///包含产品 这里会自动构建组,因为是list和directsun///</summary>[PasteDirectsun]public List<OrderProductUpdateDto> Products { get; set; }///<summary>///订单金额///</summary>[PasteDirectsun]public OrderPriceUpdateDto Price { get; set; }

我偷懒了下,直接用UpdateDto,其实应该用AddDto的,也就是

        ///<summary>///包含产品 这里会自动构建组,因为是list和directsun///</summary>[PasteDirectsun]public List<OrderProductAddDto> Products { get; set; }///<summary>///订单金额///</summary>[PasteDirectsun]public OrderPriceAddDto Price { get; set; }

不过实际中影响不大,因为我直接把对应的Id隐藏了
比如对应的OrderProductUpdateDto的代码调整如下

    ///<summary>//////</summary>public class OrderProductUpdateDto{/// <summary>/// /// </summary>[PasteHidden]public int Id { get; set; }///<summary>///商品ID///</summary>public int ProductId { get; set; }///<summary>///购买数量///</summary>public int BuyNum { get; set; }///<summary>///售价///</summary>public int ProductPrice { get; set; }///<summary>///货品信息///</summary>[PasteDirectsun]public SkuInfoUpdateDto Sku { get; set; }}

而SkuInfoUpdateDto的代码修改如下

    ///<summary>//////</summary>public class SkuInfoUpdateDto{/// <summary>/// /// </summary>[PasteHidden]public int Id { get; set; }///<summary>///货品名称///</summary>[MaxLength(32)]public string SkuName { get; set; }}

Dto解读

由上面的代码可知,主要是在子Object中加入了[PasteDirectSun]
这个其实就是特性directsun的内容,具体的可以查看
https://soft.pastecode.cn/doc/form/classfunc/directsun
(如果没有,就是我文档还没有升级哈!)
至于其他字段就是正常的字段了,不做其他说明,一起来看看如何实现新增和更新

新增

开发过ABP框架项目的都知道,新增走的是AddDto,这里就是OrderDetailAddDto
然后我们看下PasteForm在对于这个新增的时候做了什么操作
一起看下XXX.Application/levelmodels的OrderDetailAppService.cs中的
ReadAddModel
代码如下

        /// <summary>/// 读取AddDto的数据模型/// </summary>/// <returns></returns>[HttpGet][TypeFilter(typeof(RoleAttribute), Arguments = new object[] { "data", "add" })]public VoloModelInfo ReadAddModel(){var dto = new OrderDetailAddDto();dto.Products = new List<OrderProductUpdateDto> { new OrderProductUpdateDto() { Sku = new SkuInfoUpdateDto { } } };var _model = PasteBuilderHelper.DynamicReadModelProperty<OrderDetailAddDto>(dto);return _model;}

上面代码中要注意,当设计子对象的时候,需要先new一个对象出来,不然UI中没法解析对象!
估计这个问题后续会改版,就是初始化对象的问题!
这样让返回的数据格式中包含了比如Products的内容,也就是UI知道ProductUpdateDto的格式信息,以及对应的SkuInfoUpdateDto的内容!
注意,我上面解析对象用的反射是PasteBuilderHelper.DynamicReadModelProperty

新增表单

修改完成以上代码之后,我们要做一个add-migration操作
因为修改了数据库表结构等

add-migration init_database -Context SqliteDbContext

由于我本地测试使用的是Sqlite数据库
运行后,需要添加菜单

  • pasteform/index.html?path=orderDetail
    然后刷新页面后,可以点击新增,可以看到如下
    在这里插入图片描述

发现没有,字段已经对应上了,上面还有一个分组模块,叫包含产品
这个包含产品后面还有+ -,这个对应的就是Products
!!!注意,如果都点击-,一个都没有保留,那就需要刷新页面重新加载了!
我们多点击+几次,然后输入信息,大概如下

表单效果

在这里插入图片描述

点击保存!
理论上是没有错误的,提示成功,然后刷新表格页面!
点击编辑看看数据是否一致!!!
这里数据是否一致,要看查询接口,也就是

        /// <summary>/// 读取UpdateDto的数据模型/// </summary>/// <returns></returns>[HttpGet][TypeFilter(typeof(RoleAttribute), Arguments = new object[] { "data", "edit" })]public async Task<VoloModelInfo> ReadUpdateModel(int id){var _info = await _dbContext.OrderDetail.Where(x => x.Id == id).Include(x => x.Products).ThenInclude(op => op.Sku).Include(x => x.Price).AsNoTracking().FirstOrDefaultAsync();if (_info == null || _info == default){throw new PasteCodeException("查询的信息不存在,无法执行编辑操作!");}var dto = ObjectMapper.Map<OrderDetail, OrderDetailUpdateDto>(_info);var _dataModel = PasteBuilderHelper.DynamicReadModelProperty<OrderDetailUpdateDto>(dto);return _dataModel;}

看代码,是不是把Product.sku也包含进来了!!!

表格查询

上面已经例举了新增多层级表单和编辑多层级表单,那么接下来就是查询表格数据,就是按页查询数据,这里演示下包括子集的查询!

查询项配置

我们知道PasteForm框架的查询也是依托于Dto的,默认是InputQueryXXXX
本次这里的就是

    ///<summary>/// 查询///</summary>public class InputQueryOrderDetail : InputSearchBase{/// <summary>/// 货品名称/// </summary>public string sku_name { get; set; }/// <summary>/// 商品ID/// </summary>public int pro_id { get; set; }}

在默认基础上我加了2个字段查询
然后看看使用的地方

        /// <summary>/// 获取/// </summary>/// <param name="input"></param>/// <returns></returns>[HttpGet]public async Task<PagedResultDto<OrderDetailListDto>> Page([FromQuery] InputQueryOrderDetail input){var _query = _dbContext.OrderDetail.Where(t => 1 == 1).Include(x => x.Products).ThenInclude(op => op.Sku).Include(x => x.Price).WhereIf(!string.IsNullOrEmpty(input.word), x => x.Title.Contains(input.word)).WhereIf(input.pro_id != 0, x => x.Products.Any(y => y.ProductId == input.pro_id)).WhereIf(!string.IsNullOrEmpty(input.sku_name), x => x.Products.Any(y => y.Sku != null && y.Sku.SkuName.Contains(input.sku_name)));var _pagedto = new PagedResultDto<OrderDetailListDto>();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<OrderDetail>, List<OrderDetailListDto>>(dataList);_pagedto.Items = temList;return _pagedto;}

一起来看看表格中是怎样的

查询区域

在这里插入图片描述

如上所示,多了2个查询项,就是我们在InputQueryOrderDetail中添加的,所以说PasteForm添加查询就是这么简单!
测试下是否会按照输入值查询
对于前端来说就是F12看看提交的查询数据
对于后端来说,就是接受到查询条件,然后执行查询
我这测试OK!

功能回顾

有没有一种感觉,加一个表居然这么简单???
你以为上面漏了啥?实话告诉你,上面的步骤真没有漏!

!!不需要修改管理端代码,就添加了一个多级表的表单实现!!

由以上信息得知,对于多层级的Entity或者有集合的Entity的表单,对于PasteForm框架来说,可以在一个表单中完成!
需要注意的点是关于对象的实例信息,也就是进行反射Model的时候,那些对象的字段需要进行new一个默认的出来,反射才能获得对应的信息!
对于Collection来说,UI会支持±的功能!

上面回顾其实还是有可圈可点的地方

  • 1.对于字段是Object的,其实可以在解反射的时候自己new一个出来,然后解析!
  • 2.其实上面有一个冲突的地方,就是directsun的地方不能用group特性,这样会覆盖,查看前端代码可知,group要支持±的功能,需要是多层级模式!
  • 3.?是否支持->obj->items->obj->items的模式呢?等待你的测试!!!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/79107.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

深入解析分类模型评估指标:ROC曲线、AUC值、F1分数与分类报告

标题&#xff1a;深入解析分类模型评估指标&#xff1a;ROC曲线、AUC值、F1分数与分类报告 摘要&#xff1a; 在机器学习中&#xff0c;评估分类模型的性能是至关重要的一步。本文详细介绍了四个核心评估指标&#xff1a;ROC曲线、AUC值、F1分数和分类报告。通过对比这些指标…

多模态医学AI框架Pathomic Fusion,整合了组织病理学与基因组的特征

小罗碎碎念 在医学AI领域&#xff0c;癌症的精准诊断与预后预测一直是关键研究方向。 这篇文章提出了Pathomic Fusion这一创新框架&#xff0c;致力于解决现有方法的局限。 传统上&#xff0c;癌症诊断依赖组织学与基因组数据&#xff0c;但组织学分析主观易变&#xff0c;基因…

《Python星球日记》第27天:Seaborn 可视化

名人说&#xff1a;路漫漫其修远兮&#xff0c;吾将上下而求索。—— 屈原《离骚》 创作者&#xff1a;Code_流苏(CSDN)&#xff08;一个喜欢古诗词和编程的Coder&#x1f60a;&#xff09; 专栏&#xff1a;《Python星球日记》&#xff0c;限时特价订阅中ing 目录 一、Seabor…

【scikit-learn基础】--『监督学习』之 决策树回归

决策树算法是一种既可以用于分类&#xff0c;也可以用于回归的算法。 决策树回归是通过对输入特征的不断划分来建立一棵决策树&#xff0c;每一步划分都基于当前数据集的最优划分特征。 它的目标是最小化总体误差或最大化预测精度&#xff0c;其构建通常采用自上而下的贪心搜索…

解决安卓开发“No Android devices detected.”问题

解决安卓开发“No Android devices detected.”问题 ​ 当我们插入移动设备的USB时&#xff0c;却发现这并未显示已连接到的设备 点击右侧的Assistant,根据提示打开移动设备开发者模式并启用USB调试模式,然后发现我们未连接到移动设备的原因是ABD服务的原因 问题确定了&…

idea如何使用git

在 IntelliJ IDEA 中使用 Git 的详细步骤如下&#xff0c;分为配置、基础操作和高级功能&#xff0c;适合新手快速上手&#xff1a; ​一、配置 Git​ ​安装 Git​ 下载并安装 Git&#xff0c;安装时勾选“Add to PATH”。验证安装&#xff1a;终端输入 git --version 显示版本…

软件架构设计:MVC、MVP、MVVM、RIA 四大风格优劣剖析

MVC、MVP、MVVM 和 RIA 都是软件架构中常见的设计风格&#xff0c;以下是对它们的详细介绍&#xff1a; 一、MVC 架构风格&#xff08;Model - View - Controller&#xff09; 1.简介&#xff1a;MVC 架构风格将软件应用程序分为三个核心部分&#xff0c;通过这种划分来分离不…

Centos/RedHat 7.x服务器挂载ISCSI存储示例(无多路径非LVM)

客户让帮忙挂载个ISCSI存储&#xff0c;大概结构如下图所示&#xff1a; ISCSI存储为一台安装了truenas的X86服务器&#xff0c;提供存储服务的IP地址为10.16.0.1 服务器的ETH1网卡配置与10.16.0.1同段网络。 为了给客户做个简单培训&#xff0c;整理了一下操作步骤。下面是配…

TV板卡维修技术【二】

【一】测量未知MOS引脚定义的好坏 TO-252封装的MOS管子&#xff0c;上面的大焊盘是D极&#xff0c;下面的3个不同品牌的NMOS或者PMOS验证了这个结论&#xff1a; 利用这个特性&#xff0c;可以在不知道MOS引脚定义的情况下测量出MOS的好坏&#xff0c;如下图&#xff1a; 插件…

基于 cefpython 实现嵌入 Chromium (CEF)

CEF Python是一个开源项目&#xff0c;旨在为Chromium Embedded Framework提供Python绑定&#xff0c;许多流行的GUI工具包都提供了嵌入CEF浏览器&#xff0c;例如QT。 安装 pip install cefpython366.1支持的Python版本&#xff1a; 实现打开网页 from cefpython3 import…

MySQL-存储引擎和索引

1.MySQL的基础架构是什么&#xff1f; MySQL由连接器、分析器、优化器、执行器和存储引擎这五部分构成。 一条SQL的执行流程&#xff1a; 通过连接器连接数据库&#xff0c;检查用户名和密码&#xff0c;以及权限校验&#xff0c;是否有增删改查的权限。在MySQL8.0之前&#…

安卓性能调优之-掉帧测试

掉帧指的是某一帧没有在规定时间内完成渲染&#xff0c;导致 UI 画面不流畅&#xff0c;产生视觉上的卡顿、跳帧现象。 Android目标帧率&#xff1a; 一般情况下&#xff0c;Android设备的屏幕刷新率是60Hz&#xff0c;即每秒需要渲染60帧&#xff08;Frame Per Second, FPS&a…

【运维自动化-标准运维】职能化功能如何使用?

职能化功能主要用于一些固化的标准流程可以通过权限开放的方式给到那些负责固定职能的非运维人员&#xff0c;比如外包操作员来执行操作&#xff0c;如此可以释放一些运维的人力&#xff0c;让其可以专注流程的建设和优化。实操演示 新建职能化流程&#xff08;运维角色操作&a…

游戏引擎学习第224天

回顾游戏运行并指出一个明显的图像问题。 回顾一下之前那个算法 我们今天要做一点预加载的处理。上周刚完成了游戏序章部分的所有剪辑内容。在运行这一部分时&#xff0c;如果观察得足够仔细&#xff0c;就会注意到一个问题。虽然因为视频流压缩质量较低&#xff0c;很难清楚…

【小沐学GIS】基于C++绘制三维数字地球Earth(QT5、OpenGL、GIS、卫星)第五期

&#x1f37a;三维数字地球系列相关文章如下&#x1f37a;&#xff1a;1【小沐学GIS】基于C绘制三维数字地球Earth&#xff08;OpenGL、glfw、glut&#xff09;第一期2【小沐学GIS】基于C绘制三维数字地球Earth&#xff08;OpenGL、glfw、glut&#xff09;第二期3【小沐学GIS】…

OpenAI 最新发布的 GPT-4.1 系列在 API 中正式上线

每周跟踪AI热点新闻动向和震撼发展 想要探索生成式人工智能的前沿进展吗&#xff1f;订阅我们的简报&#xff0c;深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同&#xff0c;从行业内部的深度分析和实用指南中受益。不要错过这个机会&#xff0c;成为AI领…

【力扣】day1

文章目录 27.移除元素26. 删除有序数组的重复项 27.移除元素 26. 删除有序数组的重复项 我们仔细看一下这两道题的最后的返回值,为什么第一题返回slow 而第二题返回slow1 最后的返回值该如何返回绝对不是凭感觉,我们自己分析一下第一个slow,从0位置开始, 遇到val值就开始和fas…

完全无网络环境的 openEuler 系统离线安装 ClamAV 的详细步骤

准备工作&#xff08;在外网机器操作&#xff09; 1. 下载 ClamAV RPM 包及依赖 mkdir -p ~/clamav-offline/packages cd ~/clamav-offline/packages# 使用 yumdownloader 下载所有依赖包&#xff08;需提前安装 yum-utils&#xff09; sudo dnf install yum-utils -y sudo y…

3.2.2.2 Spring Boot配置视图控制器

在Spring Boot中配置视图控制器可以简化页面跳转跳逻辑。通过实现WebMvcConfigurer接口的addViewControllers方法&#xff0c;可以直接将URL映射到特定的视图&#xff0c;而无需编写控制器类。例如&#xff0c;将根路径"/"映射到welcome.html视图&#xff0c;当访问应…

数据库—函数笔记

一&#xff0c;数据库函数的分类 内置函数&#xff08;Built-in Functions&#xff09; 数据库系统自带的函数&#xff0c;无需额外定义即可直接调用。 聚合函数&#xff1a;对数据集进行计算&#xff08;如 SUM, AVG, COUNT&#xff09;。 字符串函数&#xff1a;处理文本数据…