AppBox实战: 如何实现一对多表单的增删改查

  本篇通过完整示例介绍如何实现一对多关系表单的相应服务及视图。

一、准备数据结构

  示例所采用的数据结构为“物资需求”一对多“物资清单”,通过IDE的实体设计器如下所示:

1. 物资(DonateItem)

  主键为Id(Guid)

AppBox实战: 如何实现一对多表单的增删改查

2. 物资需求(Requirement)

  主键为Id(Guid)

AppBox实战: 如何实现一对多表单的增删改查

3. 物资清单(RequireItem)

  主键为Req(Requirement)+Item(DonateItem)

AppBox实战: 如何实现一对多表单的增删改查

添加实体成员时选择类型EntityRef(一对一)或EntitySet(一对多)可设置相应的导航属性

AppBox实战: 如何实现一对多表单的增删改查

二、实现需求列表显示功能 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="联系人"></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="邮编"></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”预览,当然当前没有任何数据。

AppBox实战: 如何实现一对多表单的增删改查

三、实现新建需求功能 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"> <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="选择日期"> </el-date-picker> </el-col> </el-row> <br/> <el-row :gutter="20" type="flex"> <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"> <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="物资"> <template slot-scope="scope"> <el-select v-model="scope.row.ItemId" value-key="Id" 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="数量"> <template slot-scope="scope"> <el-input-number v-model="scope.row.Quantity" controls-position="right" :min="1"> </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> <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> <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"> <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显示物资清单

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/zzffsf.html