多表增删改查示例

本章介绍学习多张表增、删、改、查功能如何实现,下面以销货出库单作为示例,该业务栏位如下:

销货出库单栏位

  • 销货单号、销货日期、状态、客户、备注

销货出库单明细栏位

  • 商品编码、商品名称、规格型号、数量、单位、单价、金额

该示例适用于出货明细数量较小情况,单据表头和表体组合查询和提交。

对于出货明细数量较大的情况,建议表头与表体分开查询和提交,表体采用分页查询。

1. 前后端共用

1.1. 创建实体类

  • 在KIMS项目Entities文件夹下创建KmBill和KmBillList实体类
  • 该类继承EntityBase类
  • 属性使用Column特性描述,用于生成页面字段和数据校验
//销货出库单
public class KmBill : EntityBase
{
[Column("销货单号", "", true, "1", "50")]
public string? BillNo { get; set; }
......
[Column("客户", "", true, "1", "50")]
public string? BillDate { get; set; }
[Column("备注", "", false)]
public string? Note { get; set; } //出货明细,为了降低代码量,扩展实体类,不再创建DTO类
//此处使用虚属性,ORM映射SQL时忽略该属性
public virtual List<KmBillList>? Lists { get; set; }
}
//销货出库单明细
public class KmBillList : EntityBase
{
[Column("销货单ID", "", true, "1", "50")]
public string? HeadId { get; set; }
[Column("商品编码", "", true, "1", "50")]
public string? Code { get; set; }
[Column("数量", "", false)]
public decimal? Qty { get; set; }
[Column("单价", "", false)]
public decimal? Price { get; set; }
[Column("金额", "", false)]
public decimal? Amount { get; set; } //如下虚属性用于关联商品资料表查询显示
public virtual string? Name { get; set; } //商品名称
public virtual string? Model { get; set; } //规格型号
public virtual string? Unit { get; set; } //计量单位
}

1.2. 创建Client类

  • 在KIMS项目Clients文件夹下创建BillClient类
  • 该类是前后端数据交互接口,继承ClientBase类
  • 该类只需提供分页查询、删除和保存,导入功能由框架统一异步处理
public class BillClient : ClientBase
{
public BillClient(Context context) : base(context) { } public Task<PagingResult<KmBill>> QueryBillsAsync(PagingCriteria criteria) => Context.QueryAsync<KmBill>("Bill/QueryBills", criteria);
public Task<Result> DeleteBillsAsync(List<KmBill> models) => Context.PostAsync("Bill/DeleteBills", models);
public Task<KmBill> GetBillAsync(string id) => Context.GetAsync<KmBill>($"Bill/GetBill?id={id}");
public Task<Result> SaveBillAsync(KmBill model) => Context.PostAsync("Bill/SaveBill", model);
}

2. 前端

2.1. 创建List页面

  • 在KIMS.Razor项目BillData文件夹下创建BillList类
  • 该类是数据列表页面,继承WebGridView<KmBill, BillForm>类
  • 列表页面按钮和栏位在框架模块管理中配置
class BillList : WebGridView<KmBill, BillForm>
{
protected override Task InitPageAsync()
{
//表格栏位格式化显示
//销货单号链接,点击显示销货单查看表单
Column(c => c.BillNo).Template((b, r) => b.Link(r.BillNo, Callback(() => View(r))));
Column(c => c.Status).Template(BillStatusCell);//显示状态标签
return base.InitPageAsync();
} //分页查询
protected override Task<PagingResult<KmBill>> OnQueryData(PagingCriteria criteria)
{
return Client.Bill.QueryBillsAsync(criteria);
} public void New() => ShowForm();//新增按钮方法
public void DeleteM() => DeleteRows(Client.Bill.DeleteBillsAsync);//批量删除按钮方法
public void Edit(KmBill row) => ShowForm(row);//编辑操作方法
public void Delete(KmBill row) => DeleteRow(row, Client.Bill.DeleteBillsAsync);//删除操作方法
}

2.2. 创建Form页面

  • 在KIMS.Razor项目BillData\Forms文件夹下创建BillForm类
  • 该类是数据编辑和查看明细页面,继承WebForm类
[Dialog(980, 580)]//设置对话框大小
class BillForm : WebForm<KmBill>
{
private KmBill? head;
//初始化表单,查询表头表体组合数据
protected override async Task InitFormAsync()
{
var model = TModel;
head = await Client.Bill.GetBillAsync(model.Id);
}
//表单布局
protected override void BuildFields(FieldBuilder<KmBill> builder)
{
builder.Hidden(f => f.Id);//隐藏字段
builder.Table(table =>
{
table.ColGroup(11, 25, 11, 25, 11, 17);
table.Tr(attr =>
{
//销货单号不可编辑,自动生成编号
table.Field<Text>(f => f.BillNo).Enabled(false).Build();
table.Field<Date>(f => f.BillDate).Build();
table.Field<Text>(f => f.Status).Enabled(false).Build();
});
table.Tr(attr => table.Field<TextArea>(f => f.Note).ColSpan(5).Build());
builder.FormList<BillListGrid>("商品明细", "", attr =>
{
attr.Set(c => c.ReadOnly, ReadOnly)
.Set(c => c.Data, head?.Lists);//设置表体数据
});
});
}
//表单底部按钮
protected override void BuildButtons(RenderTreeBuilder builder)
{
builder.Button(FormButton.Save, Callback(OnSave), !ReadOnly);
base.BuildButtons(builder);
}
//保存按钮方法
private void OnSave()
{
SubmitAsync(data =>
{
head?.FillModel(data);//自动填充表单修改数据
return Client.Bill.SaveBillAsync(head);
});
}
}

2.3. 创建表体页面

  • 在KIMS.Razor项目BillData\Forms文件夹下创建BillListGrid类
  • 该类是表体数据编辑表格,继承EditGrid类
//可编辑表体组件
class BillListGrid : EditGrid<KmBillList>
{
public BillListGrid()
{
OrderBy = nameof(KmBillList.ItemNo);//默认排序
Name = "商品明细";
}
//初始化表格栏位
protected override Task OnInitializedAsync()
{
//如下栏位有Edit方法为可编辑栏位,否则不可编辑
var builder = new ColumnBuilder<KmBillList>();
//商品库存选择器,弹出对话框查询商品库存,双击选择要出库的商品
builder.Field(r => r.Code).Edit(new GoodsStock(), OnCodeChanged);
builder.Field(r => r.Name);//不可编辑
builder.Field(r => r.Model);
builder.Field(r => r.Qty).Edit<Number>(OnQtyChanged);//可编辑
builder.Field(r => r.Unit);
builder.Field(r => r.Price).Edit<Number>(OnPriceChanged);
builder.Field(r => r.Amount).IsSum().Edit<Number>(OnAmountChanged);
builder.Field(r => r.Note).Edit();
Columns = builder.ToColumns();
return base.OnInitializedAsync();
}
//切换商品编码,自动带出商品信息
private void OnCodeChanged(KmBillList row, object value)
{
var g = value as StockInfo;
row.Type = g?.Type;
row.Code = g?.Code;
row.Name = g?.Name;
row.Model = g?.Model;
row.Unit = g?.Unit;
}
//更改数量,自动计算金额
private void OnQtyChanged(KmBillList row, object value)
{
var qty = Utils.ConvertTo<decimal>(value);
row.Amount = Utils.Round(qty * (row.Price ?? 0), 2);
}
//更改单价,自动计算金额
private void OnPriceChanged(KmBillList row, object value)
{
var price = Utils.ConvertTo<decimal>(value);
row.Amount = Utils.Round(price * row.Qty, 2);
}
//更改金额,自动计算单价
private void OnAmountChanged(KmBillList row, object value)
{
var amount = Utils.ConvertTo<decimal>(value);
row.Price = row.Qty == 0 ? 0 : Utils.Round(amount / row.Qty, 2);
}
}

3. 后端

3.1. 创建Controller类

  • 在KIMS.Core项目Controllers文件夹下创建BillController类
  • 该类为服务端WebApi,继承BaseController类
[Route("[controller]")]
public class BillController : BaseController
{
private BillService Service => new(Context); [HttpPost("[action]")]
public PagingResult<KmBill> QueryBills([FromBody] PagingCriteria criteria) => Service.QueryBills(criteria); [HttpPost("[action]")]
public Result DeleteBills([FromBody] List<KmBill> models) => Service.DeleteBills(models); [HttpGet("[action]")]
public KmBill GetBill([FromQuery] string id) => Service.GetBill(id); [HttpPost("[action]")]
public Result SaveBill([FromBody] KmBill model) => Service.SaveBill(model);
}

3.2. 创建Service类

  • 在KIMS.Core项目Services文件夹下创建BillService类
  • 该类为业务逻辑服务类,继承ServiceBase类
class BillService : ServiceBase
{
internal BillService(Context context) : base(context) { }
//分页查询
internal PagingResult<KmBill> QueryBills(PagingCriteria criteria)
{
return BillRepository.QueryBills(Database, criteria);
}
//删除数据
internal Result DeleteBills(List<KmBill> models)
{
if (models == null || models.Count == 0)
return Result.Error(Language.SelectOneAtLeast); //此处增加删除数据校验
return Database.Transaction(Language.Delete, db =>
{
foreach (var item in models)
{
//删除表体
BillRepository.DeleteBillLists(db, item.Id);
db.Delete(item);
}
});
}
//获取组合数据
internal KmBill GetBill(string id)
{
if (string.IsNullOrEmpty(id))//id为空返回默认值
return GetDefaultBill(); var entity = Database.QueryById<KmBill>(id);
if (entity == null)//为空返回默认值
entity = GetDefaultBill();
else//否则组装表体数据返回
entity.Lists = BillRepository.GetBillLists(Database, id);
return entity;
}
//保存数据
internal Result SaveBill(KmBill model)
{
if (model == null)
return Result.Error("不能提交空数据!"); var vr = model.Validate();//验证输入栏位
if (!vr.IsValid)
return vr; return Database.Transaction(Language.Save, db =>
{
if (model.IsNew)
model.BillNo = GetBillMaxNo(db); //清空表体合计数据
model.TotalAmount = 0;
model.GoodsName = string.Empty;
//先删除表体,再插入表体
BillRepository.DeleteBillLists(db, model.Id);
if (model.Lists != null && model.Lists.Count > 0)
{
var index = 0;
var lists = new List<KmBillList>();
foreach (var item in model.Lists)
{
if (isReturn && item.Qty == 0)
continue; item.HeadId = model.Id;
item.ItemNo = ++index;
db.Insert(item);
lists.Add(item);
}
//合计表体数据
model.TotalAmount = lists.Sum(l => l.Amount);
model.GoodsName = string.Join(",", lists.Select(l => l.Name));
}
db.Save(model);
}, model);
}
//获取默认表头
private KmBill GetDefaultBill()
{
return new KmBill
{
BillNo = GetBillMaxNo(Database),
BillDate = DateTime.Now,
Status = "暂存",
Lists = new List<JxBillList>()
};
}
//获取销货单最大编号
private static string GetBillMaxNo(Database db)
{
var prefix = $"S{DateTime.Now:yyyy}";
var maxNo = BillRepository.GetBillMaxNo(db, prefix);
if (string.IsNullOrWhiteSpace(maxNo))
maxNo = $"{prefix}00000";
return GetMaxFormNo(prefix, maxNo);
}
}

3.3. 创建Repository类

  • 在KIMS.Core项目Repositories文件夹下创建BillRepository类
  • 该类为数据访问类
class BillRepository
{
//Head
//分页查询
internal static PagingResult<KmBill> QueryBills(Database db, PagingCriteria criteria)
{
var sql = "select * from KmBill where CompNo=@CompNo";
return db.QueryPage<KmBill>(sql, criteria);//查询条件自动绑定
}
//获取销货单最大编号
internal static string GetBillMaxNo(Database db, string prefix)
{
var sql = $"select max(BillNo) from KmBill where CompNo=@CompNo and BillNo like '{prefix}%'";
return db.Scalar<string>(sql, new { db.User.CompNo });
}
//List
//根据表头ID获取表体数据
internal static List<KmBillList> GetBillLists(Database db, string headId)
{
//关联商品资料表查询商品信息
var sql = "select a.*,b.Name,b.Model,b.Unit from KmBillList a,KmGoods b where a.Code=b.Code and HeadId=@headId";
return db.QueryList<KmBillList>(sql, new { headId });
}
//根据表头ID删除表体数据
internal static void DeleteBillLists(Database db, string headId)
{
var sql = "delete from KmBillList where HeadId=@headId";
db.Execute(sql, new { headId });
}
}

4. 运行测试

  • 运行效果如下



Blazor实战——Known框架多表增删改查的更多相关文章

  1. SSH框架下的多表增删改查

    下载地址:SSH框架下的多表增删改查 点击进入码云Git下载 点击进入CSDN下载 项目结构: 项目代码就不全部贴出来了,只贴下核心代码.需要项目的自己可以去下载. package com.atgui ...

  2. Django框架(八)--单表增删改查,在Python脚本中调用Django环境

    一.数据库连接配置 如果连接的是pycharm默认的Sqlite,不用改动,使用默认配置即可 如果连接mysql,需要在配置文件中的setting中进行配置: 将DATABASES={} 更新为 DA ...

  3. Django框架(九)—— 单表增删改查,在Python脚本中调用Django环境

    目录 单表增删改查,在Python脚本中调用Django环境 一.数据库连接配置 二.orm创建表和字段 三.单表增删改查 1.增加数据 2.删除数据 3.修改数据 4.查询数据 四.在Python脚 ...

  4. Spring JdbcTemplate框架搭建及其增删改查使用指南

    Spring JdbcTemplate框架搭建及其增删改查使用指南 前言: 本文指在介绍spring框架中的JdbcTemplate类的使用方法,涉及基本的Spring反转控制的使用方法和JDBC的基 ...

  5. Django框架简单搭建增删改查页面 Django请求生命周期流程图

    目录 Django框架简单搭建增删改查页面 一.前期的配置文件以及连接MySQL的基本准备 二.在数据库中准备好数据 三.将MySQL的数据展示到页面(简单认识HTML模板语法 for循环) 在Dja ...

  6. GZFramwork数据库层《四》单据主从表增删改查

    同GZFramwork数据库层<三>普通主从表增删改查 不同之处在于:实例 修改为: 直接上效果: 本系列项目源码下载地址:https://github.com/GarsonZhang/G ...

  7. GZFramwork数据库层《三》普通主从表增删改查

    运行结果: 使用代码生成器(GZCodeGenerate)生成tb_Cusomer和tb_CusomerDetail的Model 生成器源代码下载地址: https://github.com/Gars ...

  8. GZFramwork数据库层《二》单据表增删改查(自动生成单据号码)

    运行效果: 使用代码生成器(GZCodeGenerate)生成tb_EmpLeave的Model 生成器源代码下载地址: https://github.com/GarsonZhang/GZCodeGe ...

  9. GZFramwork数据库层《一》普通表增删改查

    运行结果:     使用代码生成器(GZCodeGenerate)生成tb_MyUser的Model 生成器源代码下载地址: https://github.com/GarsonZhang/GZCode ...

  10. Vc数据库编程基础MySql数据库的表增删改查数据

    Vc数据库编程基础MySql数据库的表增删改查数据 一丶表操作命令 1.查看表中所有数据 select * from 表名 2.为表中所有的字段添加数据 insert into 表名( 字段1,字段2 ...

随机推荐

  1. Hystrix 如何在不引入 Archaius 的前提下实现动态配置更新

    Hystrix 简介 Hystrix 是 Netflix 开源的一个限流熔断降级组件,防止依赖服务发生错误后,将调用方的服务拖垮.这里对 Hystrix 本身不做过多介绍. Hystrix 目前处于维 ...

  2. 学习笔记——树形dp

    树形 dp 介绍 概念 树形 dp,顾名思义,就是在树上做 dp,将 dp 的思想建立在树状结构之上. 常见的树形 dp 有两种转移方向: 从叶节点向根节点转移,这种也是树形 dp 中较为常见的一种. ...

  3. C# 打开蓝牙设置界面

    蓝牙设置相关界面,以下是通过C#方式打开的几个方式,记录一下 蓝牙设置界面 1.控制面板命令bthprops.cpl 可以用控制面板 control+bthprops.cpl,也可以直接bthprop ...

  4. TED--10 ways to have a better conversation

    10 ways to have a better conversation All right, I want to see a show of hands: how many of you have ...

  5. 【性能】JDK和Jmeter的安装与配置

    一.JDK环境配置 1. 下载JDK 官网下载地址:http://www.oracle.com/technetwork/java/javase/downloads/java-archive-downl ...

  6. 云原生时代崛起的编程语言Go并发编程实战

    @ 目录 概述 基础理论 并发原语 协程-Goroutine 通道-Channel 多路复用-Select 通道使用 超时-Timeout 非阻塞通道操作 关闭通道 通道迭代 定时器-TimerAnd ...

  7. UIOTOS:一款无门槛的前端0代码搭建工具

    什么是UIOTOS? UIOTOS中文名称前端大师,是一款基于图形技术的前端0代码工具,支持通过连线和嵌套无门槛来搭建各类复杂的的交互界面,包括后台管理系统.组态数据大屏等,实现跟代码开发媲美的效果. ...

  8. 【Docker】容器管理

    一.容器生命周期及启动过程 1.容器生命周期 2.容器启动过程 二.容器管理命令 Usage: docker [OPTIONS] COMMAND A self-sufficient runtime f ...

  9. 2022-09-17:一个字符串s,表示仓库的墙 与 货物,其中‘|‘表示墙,‘*‘表示货物。 给定一个起始下标start和一个终止下标end, 找出子串中 被墙包裹的货物 数量。 比如: s = “

    2022-09-17:一个字符串s,表示仓库的墙 与 货物,其中'|'表示墙,''表示货物. 给定一个起始下标start和一个终止下标end, 找出子串中 被墙包裹的货物 数量. 比如: s = &q ...

  10. 2021-12-27:给定一个字符串str,和一个正数k, str子序列的字符种数必须是k种,返回有多少子序列满足这个条件。 已知str中都是小写字母, 原始是取mod, 本节在尝试上,最难的, 搞出

    2021-12-27:给定一个字符串str,和一个正数k, str子序列的字符种数必须是k种,返回有多少子序列满足这个条件. 已知str中都是小写字母, 原始是取mod, 本节在尝试上,最难的, 搞出 ...