java表单一对多保存功能_AppBoxFuture实战: 如何实现一对多表单的增删改查

本文详细介绍了如何使用Java实现一对多关系的表单操作,包括服务端的数据结构、列表显示、新建需求、编辑视图、删除功能,以及前端的Vue组件设计。示例中涉及物资需求和物资清单的一对多关系,通过DataStore进行数据操作,并展示了前后端交互的实现过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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

一、准备数据结构

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

1. 物资(DonateItem)

主键为Id(Guid)

0e01754406bfeb8ed26654fcb0b63493.png

2. 物资需求(Requirement)

主键为Id(Guid)

8625b0340b79a19b35f7b9c7306a3327.png

3. 物资清单(RequireItem)

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

398cb7018bf585af4323fbcf304be358.png

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

ff5d659866ee71181b79c3ef35c1185f.png

二、实现需求列表显示功能

1. 新建RequirementService服务实现加载列表数据

using System;

using System.Threading.Tasks;

namespace dns.ServiceLogic

{

public class RequirementService

{

///

/// 分页加载需求记录

///

public async Task Load(int pageIndex, int pageSize)

{

var q = new SqlQuery();

q.Skip(pageSize * pageIndex).Take(pageSize);

q.OrderByDesc(t => t.Time);

return await q.ToListAsync();

}

}

}

2. 新建RequireList视图

2.1 模版

新建

修改

删除

刷新

readonly>

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”预览,当然当前没有任何数据。

a689fc24ecceee33be0dacd72882f8d4.png

三、实现新建需求功能

3.1 修改RequirementService实现保存方法

///

/// 保存需求

///

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

{

///

/// 加载用于前端选择绑定

///

public async Task LoadForSelect()

{

var q = new SqlQuery();

return await q.ToListAsync(t => new { t.Id, t.Name, t.Spec });

}

}

}

3.3 新建RequireView编辑视图

3.3.1 模版

需求方:

时间:

联系人:

电话:

地址:

邮编:

:value="item.Id">

添加

删除

保存

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 模版

新建

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服务实现加载子表数据方法

///

/// 加载需求物资列表

///

public async Task LoadItems(Guid reqId)

{

var q = new SqlQuery();

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 模版

{{index+1}}.

{{item.ItemName}}

{{item.ItemSpec}}

{{item.Quantity}}

物资清单

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 预览

0bccb77c6a3df84b214826e2c537bda7.png

五、实现修改与删除功能

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();

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 模版

修改

删除

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 预览

ab35a043e5e0f5b40f251c02419c5824.png

六、本篇小结

作者上篇提到实现独立的不依赖内置存储的版本,本篇示例即是基于此版本,下一步重点是针对此版本的测试与Bug修复。另一边码代码一边码文实属不易,作者需要您的支持请您多多点赞推荐!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值