AppBox实战: 如何实现一对多表单的增删改查
本篇通过完整示例介绍如何实现一对多关系表单的相应服务及视图。
一、准备数据结构
示例所采用的数据结构为“物资需求”一对多“物资清单”,通过IDE的实体设计器如下所示:
1. 物资(DonateItem)
主键为Id(Guid)
2. 物资需求(Requirement)
主键为Id(Guid)
3. 物资清单(RequireItem)
主键为Req(Requirement)+Item(DonateItem)
添加实体成员时选择类型EntityRef(一对一)或EntitySet(一对多)可设置相应的导航属性
二、实现需求列表显示功能
1. 新建RequirementService服务实现加载列表数据
using System;
using System.Threading.Tasks;
namespace dns.ServiceLogic
{
public class RequirementService
{
/// <summary>
/// 分页加载需求记录
/// </summary>
public async Task<object> Load(int pageIndex, int pageSize)
{
var q = new SqlQuery<Entities.Requirement>();
q.Skip(pageSize * pageIndex).Take(pageSize);
q.OrderByDesc(t => t.Time);
return await q.ToListAsync();
}
}
}
2. 新建RequireList视图
2.1 模版
<div>
<el-button-group>
<el-button type="primary" icon="fas fa-plus-square fa-fw">新建</el-button>
<el-button type="primary" icon="fas fa-edit fa-fw">修改</el-button>
<el-button type="primary" icon="fas fa-trash fa-fw">删除</el-button>
<el-button @click="load" type="primary" icon="fas fa-search fa-fw">刷新</el-button>
</el-button-group>
<br/><br/>
<el-table :data="items" v-loading="loading" border stripe highlight-current-row
readonly>
<el-table-column prop="Donee" label="需求方"></el-table-column>
<el-table-column prop="Time" label="时间"></el-table-column>
<el-table-column prop="Contact" label="联系人" width="80"></el-table-column>
<el-table-column prop="Phone" label="电话"></el-table-column>
<el-table-column prop="Address" label="地址"></el-table-column>
<el-table-column prop="PostCode" label="邮编" width="80"></el-table-column>
</el-table>
<el-pagination background layout="prev, pager, next" :total="1000">
</el-pagination>
</div>
2.2 脚本
@Component
export default class RequireList extends Vue {
items = [] //需求列表
loading = false
pageIndex = 0
pageSize = 20
load() {
this.loading = true
dns.Services.RequirementService.Load(this.pageIndex, this.pageSize).then(res => {
this.$set(this, 'items', $runtime.parseEntity(res))
this.loading = false
}).catch(err => {
this.loading = false
this.$message.error('加载需求列表失败: ' + err)
})
}
mounted() {
this.load()
}
}
系统函数$runtime.parseEntity()用于将调用服务的结果内的数据对象如{ID:xxx,Name:xxx}转换为前端的Entity对象,另如果调用服务的结果只用作展示可以不用转换。
2.3 预览
点击“Preview”预览,当然当前没有任何数据。
三、实现新建需求功能
3.1 修改RequirementService实现保存方法
/// <summary>
/// 保存需求
/// </summary>
public async Task Save(Entities.Requirement req)
{
//TODO:验证
using var conn = await DataStore.Default.OpenConnectionAsync();
using var txn = conn.BeginTransaction();
//保存主记录
await DataStore.Default.SaveAsync(req, txn);
//保存子记录
foreach (var item in req.Items)
{
await DataStore.Default.SaveAsync(item, txn);
}
//处理已删除的物资
if (req.PersistentState != PersistentState.Detached)
{
foreach (var item in req.Items.DeletedItems)
{
await DataStore.Default.DeleteAsync(item, txn);
}
}
//递交事务
txn.Commit();
}
3.2 新建ItemService实现用于绑定的加载方法
using System;
using System.Threading.Tasks;
namespace dns.ServiceLogic
{
public class ItemService
{
/// <summary>
/// 加载用于前端选择绑定
/// </summary>
public async Task<object> LoadForSelect()
{
var q = new SqlQuery<Entities.DonateItem>();
return await q.ToListAsync(t => new { t.Id, t.Name, t.Spec });
}
}
}
3.3 新建RequireView编辑视图
3.3.1 模版
<div>
<!-- 表单头 -->
<el-row :gutter="20" type="flex" align="middle">
<el-col :span="3">需求方:</el-col>
<el-col :span="9">
<el-input v-model="req.Donee"></el-input>
</el-col>
<el-col :span="3">时间:</el-col>
<el-col :span="9">
<el-date-picker v-model="req.Time" type="date" placeholder="选择日期" style="width:100%">
</el-date-picker>
</el-col>
</el-row>
<br/>
<el-row :gutter="20" type="flex" align="middle">
<el-col :span="3">联系人:</el-col>
<el-col :span="9">
<el-input v-model="req.Contact"></el-input>
</el-col>
<el-col :span="3">电话:</el-col>
<el-col :span="9">
<el-input v-model="req.Phone"></el-input>
</el-col>
</el-row>
<br/>
<el-row :gutter="20" type="flex" align="middle">
<el-col :span="3">地址:</el-col>
<el-col :span="9">
<el-input v-model="req.Address"></el-input>
</el-col>
<el-col :span="3">邮编:</el-col>
<el-col :span="9">
<el-input v-model="req.PostCode"></el-input>
</el-col>
</el-row>
<br/>
<!-- 物资列表 -->
<el-table :data="items" border highlight-current-row readonly>
<el-table-column type="index"></el-table-column>
<el-table-column label="物资" width="280px">
<template slot-scope="scope">
<el-select v-model="scope.row.ItemId" value-key="Id" style="width:100%" placeholder="请选择">
<el-option v-for="item in optItems" :key="item.Id" :label="item.Name+' '+item.Spec"
:value="item.Id">
</el-option>
</el-select>
</template>
</el-table-column>
<el-table-column label="数量" width="130px">
<template slot-scope="scope">
<el-input-number v-model="scope.row.Quantity" controls-position="right" :min="1" style="width:100%">
</el-input-number>
</template>
</el-table-column>
<el-table-column label="备注">
<template slot-scope="scope">
<el-input v-model="scope.row.Comment"></el-input>
</template>
</el-table-column>
<el-table-column align="right" width="100px">
<template slot="header" slot-scope="scope">
<el-button @click="onAddItem" icon="fa fa-plus fa-fw" size="mini">添加</el-button>
</template>
<template slot-scope="scope">
<el-button @click="onDeleteItem(scope.$index)" icon="fa fa-times fa-fw" size="mini">删除</el-button>
</template>
</el-table-column>
</el-table>
<br/>
<div style="text-align:center">
<el-button @click="onSave" type="primary" icon="fas fa-save fa-fw">保存</el-button>
</div>
</div>
3.3.2 脚本
@Component
export default class RequireView extends Vue {
@Prop({ type: Object, default: {} }) req: dns.Entities.Requirement
optItems = [] //物资选择列表
/** 用于Table绑定,过滤已标为删除的 */
get items() {
if (this.req.Items) {
return this.req.Items.filter(t => !t.isDeleted())
}
return null
}
/** 加载用于绑定下拉选择的物资列表 */
loadItems() {
dns.Services.ItemService.LoadForSelect().then(res => {
this.$set(this, 'optItems', res)
}).catch(err => {
this.$message.error("加载物资列表失败: " + err)
})
}
/** 添加物资 */
onAddItem() {
if (!this.req.Items) { //仅测试
this.$set(this.req, 'Items', [])
}
this.req.Items.push(new dns.Entities.RequireItem())
}
/** 删除物资 */
onDeleteItem(index) {
//新建的直接删除,旧的标为删除
if (this.req.Items[index].isNew()) {
this.req.Items.splice(index, 1)
} else {
this.req.Items[index].markDeleted()
}
}
onSave() {
dns.Services.RequirementService.Save(this.req).then(res => {
this.req.acceptChanges()
this.$message.success("保存成功")
}).catch(err => {
this.$message.error("保存错误: " + err)
})
}
mounted() {
this.loadItems()
}
}
3.4 修改RequireList视图,实现新建功能
3.4.1 模版
<el-button @click="onCreate" type="primary" icon="fas fa-plus-square fa-fw">新建</el-button>
<!-- 省略 -->
<el-dialog title="需求记录" :visible.sync="dlgVisible" width="800px">
<require-view :req="current"></require-view>
</el-dialog>
<!-- 省略 -->
3.4.2 脚本
@Component({
components: { RequireView: dns.Views.RequireView }
})
export default class RequireList extends Vue {
//----省略----
dlgVisible = false
current = null
//----省略----
onCreate() {
this.current = new dns.Entities.Requirement()
this.dlgVisible = true
}
//----省略----
现在可以在预览内尝试添加些数据了!
四、实现需求列表Pop显示物资清单
主列表使用懒加载方式加载子表数据。
4.1 修改RequirementService服务实现加载子表数据方法
/// <summary>
/// 加载需求物资列表
/// </summary>
public async Task<object> LoadItems(Guid reqId)
{
var q = new SqlQuery<Entities.RequireItem>();
q.Where(t => t.ReqId == reqId);
q.Include(t => t.Item.Name);
q.Include(t => t.Item.Spec);
return await q.ToListAsync();
}
4.2 修改RequireList视图
4.2.1 模版
<!-- 省略 -->
<el-table-column label="需求物资" width="80">
<template slot-scope="scope">
<!-- 物资清单列表 -->
<el-popover @show="loadItems(scope.row)" trigger="hover" placement="left" width="400">
<el-row v-for="(item,index) in scope.row.Items" :gutter="20">
<el-col :span="2">{{index+1}}.</el-col>
<el-col :span="4">{{item.ItemName}}</el-col>
<el-col :span="14">{{item.ItemSpec}}</el-col>
<el-col :span="4">{{item.Quantity}}</el-col>
</el-row>
<div slot="reference">
<el-tag size="medium">物资清单</el-tag>
</div>
</el-popover>
</template>
</el-table-column>
<!-- 省略 -->
4.2.2 脚本
/** 加载需求物资清单 */
loadItems(row: dns.Entities.Requirement) {
if (row.Items) { return }
dns.Services.RequirementService.LoadItems(row.Id).then(res => {
this.$set(row, 'Items', $runtime.parseEntity(res))
}).catch(err => {
this.$message.error('加载物资列表失败: ' + err)
})
}
4.2.3 预览
五、实现修改与删除功能
5.1 修改RequirementService服务实现删除方法
public async Task Delete(Entities.Requirement req)
{
//TODO:判断状态,已发放物资的不能删除
using var conn = await DataStore.Default.OpenConnectionAsync();
using var txn = conn.BeginTransaction();
//先删除子表记录
var deleteItems = new SqlDeleteCommand<Entities.RequireItem>();
deleteItems.Where(t => t.ReqId == req.Id);
await DataStore.Default.ExecCommandAsync(deleteItems, txn);
//再删除主表记录
await DataStore.Default.DeleteAsync(req, txn);
//递交事务
txn.Commit();
}
5.2 修改RequireList视图
5.2.1 模版
<!-- 省略 -->
<el-button @click="onEdit" type="primary" icon="fas fa-edit fa-fw">修改</el-button>
<el-button @click="onDelete" type="primary" icon="fas fa-trash fa-fw">删除</el-button>
<!-- 省略 -->
<el-table :data="items" v-loading="loading" @current-change="onCurrentChanged" border stripe highlight-current-row
readonly>
5.2.2 脚本
//----省略----
export default class RequireList extends Vue {
//----省略----
currentRow = null
//----省略----
onCurrentChanged(row) {
this.currentRow = row
}
onEdit() {
if (!this.currentRow) {
this.$message.warning("请先选择记录")
return
}
this.loadItems(this.currentRow)
this.current = this.currentRow
this.dlgVisible = true
}
onDelete() {
if (!this.currentRow) {
this.$message.warning("请先选择记录")
return
}
this.$confirm('确认删除选择的记录吗?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
dns.Services.RequirementService.Delete(this.currentRow).then(res => {
this.$message.success("删除成功");
}).catch(err => {
this.$message.error("删除失败: " + err)
})
}).catch(() => { })
}
//----省略----
5.2.3 预览
六、本篇小结
作者上篇提到实现独立的不依赖内置存储的版本,本篇示例即是基于此版本,下一步重点是针对此版本的测试与Bug修复。另一边码代码一边码文实属不易,作者需要您的支持请您多多点赞推荐!
AppBox实战: 如何实现一对多表单的增删改查的更多相关文章
- vue.js带复选框表单的增删改查
近段时间由于公司项目要求,前端开始使用VUE框架进行开发,最近刚开始学习,做了一个表单的增删改查,和大家分享一下. 页面模型代码设计如下 <template> <div id=&qu ...
- django-orm框架表单的增删改查
08.14自我总结 django-orm框架 一.orm基本配置 1.创建django项目 命令行:cmd先去到django创建目录,然后输入django-admin startproject dja ...
- Django框架之第二篇--app注册、静态文件配置、form表单提交、pycharm连接数据库、django使用mysql数据库、表字段的增删改查、表数据的增删改查
本节知识点大致为:静态文件配置.form表单提交数据后端如何获取.request方法.pycharm连接数据库,django使用mysql数据库.表字段的增删改查.表数据的增删改查 一.创建app,创 ...
- Online Coding开发模式 (通过在线配置实现一个表模型的增删改查功能,无需写任何代码)
JEECG 智能开发平台. 开发模式由代码生成器转变为Online Coding模式 (通过在线配置实现一个表模型的增删改查功能,无需一行代码,支持用户自定义 ...
- shell编程系列22--shell操作数据库实战之shell脚本与MySQL数据库交互(增删改查)
shell编程系列22--shell操作数据库实战之shell脚本与MySQL数据库交互(增删改查) Shell脚本与MySQL数据库交互(增删改查) # 环境准备:安装mariadb 数据库 [ro ...
- Maven+SSM框架,实现单表简单的增删改查
目录 1.创建web Maven项目 2.创建java源码文件和resources资源文件 3.创建数据库配置文件:jdbc.properties 4.项目总体目录: 5.添加spring配置文件:a ...
- SQLAlchemy表操作和增删改查
一.SQLAlchemy介绍 SQLAlchemy是一个基于Python实现的ORM框架.该框架建立在 DB API之上,使用关系对象映射进行数据库操作,简言之便是:将类和对象转换成SQL,然后使用数 ...
- EF Codefirst 中间表(关系表)的增删改查(转)
EF Codefirst 多对多关系 操作中间表的 增删改查(CRUD) 前言 此文章只是为了给新手程序员,和经验不多的程序员,在学习ef和lambada表达式的过程中可能遇到的问题. 本次使用订 ...
- java实现单链表增删改查
package 数据结构算法.链表; /* *定义节点 * 链表由节点构成 */ public class Node<E> { private E e; //数据data private ...
随机推荐
- 【一起学源码-微服务】Feign 源码二:Feign动态代理构造过程
前言 前情回顾 上一讲主要看了@EnableFeignClients中的registerBeanDefinitions()方法,这里面主要是 将EnableFeignClients注解对应的配置属性注 ...
- 【转】Matlab多项式拟合
转:https://blog.csdn.net/hwecc/article/details/80308397 例: x = [0.33, 1.12, 1.41, 1.71, 2.19] y = [0. ...
- 使用内存映射文件MMF实现大数据量导出时的内存优化
前言 导出功能几乎是所有应用系统必不可少功能,今天我们来谈一谈,如何使用内存映射文件MMF进行内存优化,本文重点介绍使用方法,相关原理可以参考文末的连接 实现 我们以单次导出一个excel举例(csv ...
- 用Python爬取了考研吧1000条帖子,原来他们都在讨论这些!
写在前面 考研在即,想多了解考研er的想法,就是去找学长学姐或者去网上搜索,贴吧就是一个好地方.而借助强大的工具可以快速从网络鱼龙混杂的信息中得到有价值的信息.虽然网上有很多爬取百度贴吧的教程和例子, ...
- pom文件继承与聚合
1.简介 pom.xml文件是Maven进行工作的主要配置文件.在这个文件中我们可以配置Maven项目的groupId.artifactId和version等Maven项目必须的元素:可以配置Mave ...
- SpringSecurity 默认表单登录页展示流程源码
SpringSecurity 默认表单登录页展示流程源码 本篇主要讲解 SpringSecurity提供的默认表单登录页 它是如何展示的的流程, 涉及 1.FilterSecurityIntercep ...
- 修改现有消息类让.net core项目支持Protobuf - 【无需使用 [ProtoBuf.ProtoContract] 的方法】
前言 第二次发博客,希望大家多多鼓励!!! 又接无上老板的一个需求,需要让.net core消息发送端跟消息接收端通信的消息是protobuf格式的(基于protobuf比json小一倍数据量,独特的 ...
- Android的学习之路一
在Android的道路上越走越远==,本着一颗童心去学习,没想到最后会成为自己的职业.看到过知乎上写的,并不是兴趣使比尔盖茨以及乔布斯他们成就斐然,而是他们真正的牛逼使得即使买大饼也能成为世界首富.然 ...
- Python+Flask+MysqL的web技术建站过程
1.个人学期总结 时间过得飞快,转眼间2017年就要过去.这一年,我学习JSP和Python,哪一门都像一样新的东西,之前从来没有学习过. 这里我就用我学习过的Python和大家分享一下,我是怎么从一 ...
- JS-08-对象
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title> ...