Blazor实战——Known框架增删改查导
本章介绍学习增、删、改、查、导功能如何实现,下面以商品资料作为示例,该业务栏位如下:
类型、编码、名称、规格、单位、库存下限、库存上限、备注
1. 前后端共用
1.1. 创建实体类
- 在KIMS项目Entities文件夹下创建KmGoods实体类
- 该类继承EntityBase类
- 属性使用Column特性描述,用于生成页面字段和数据校验
public class KmGoods : EntityBase
{
[Column("商品类型", "", true, "1", "50")]
public string? Type { get; set; }
......
[Column("库存下限", "", false)]
public decimal? MinStock { get; set; }
......
[Column("备注", "", false)]
public string? Note { get; set; }
}
1.2. 创建Client类
- 在KIMS项目Clients文件夹下创建GoodsClient类
- 该类是前后端数据交互接口,继承BaseClient类
- 该类只需提供分页查询、删除和保存,导入功能由框架统一异步处理
public class GoodsClient : BaseClient
{
public GoodsClient(Context context) : base(context) { }
public Task<PagingResult<KmGoods>> QueryGoodsesAsync(PagingCriteria criteria) => Context.QueryAsync<KmGoods>("Goods/QueryGoodses", criteria);
public Task<Result> DeleteGoodsesAsync(List<KmGoods> models) => Context.PostAsync("Goods/DeleteGoodses", models);
public Task<Result> SaveGoodsAsync(object model) => Context.PostAsync("Goods/SaveGoods", model);
}
2. 前端
2.1. 创建List页面
- 在KIMS.Razor项目BaseData文件夹下创建GoodsList类
- 该类是数据列表页面,继承WebGridView<KmGoods, GoodsForm>类
- 列表页面按钮和栏位在框架模块管理中配置
class GoodsList : WebGridView<KmGoods, GoodsForm>
{
//分页查询
protected override Task<PagingResult<KmGoods>> OnQueryData(PagingCriteria criteria)
{
return Client.Goods.QueryGoodsesAsync(criteria);
}
//表格栏位格式化显示
protected override void FormatColumns()
{
Column(c => c.Type).Select(new SelectOption { Codes = AppDictionary.GoodsType });
Column(c => c.TaxRate).Template((b, r) => b.Text(r.TaxRate?.ToString("P")));
}
public void New() => ShowForm();//新增按钮方法
public void DeleteM() => OnDeleteM(Client.Goods.DeleteGoodsesAsync);//批量删除按钮方法
public void Edit(KmGoods row) => ShowForm(row);//编辑操作方法
public void Delete(KmGoods row) => OnDelete(row, Client.Goods.DeleteGoodsesAsync);//删除操作方法
}
2.2. 创建Form页面
- 在KIMS.Razor项目BaseData\Forms文件夹下创建GoodsForm类
- 该类是数据编辑和查看明细页面,继承WebForm类
[Dialog(800, 420)]//设置对话框大小
class GoodsForm : WebForm<KmGoods>
{
//表单布局
protected override void BuildFields(FieldBuilder<KmGoods> builder)
{
builder.Hidden(f => f.Id);//隐藏字段
builder.Table(table =>
{
table.ColGroup(15, 35, 15, 35);
table.Tr(attr =>
{
builder.Field<Text>(f => f.Code).Enabled(TModel.IsNew).Build();//编码,编辑时灰显
builder.Field<Text>(f => f.Name).Build();
});
table.Tr(attr =>
{
builder.Field<Select>(f => f.Type).Set(f => f.Codes, AppDictionary.GoodsType).Build();//下拉框
builder.Field<Select>(f => f.Unit).Set(f => f.Codes, AppDictionary.GoodsUnit).Build();
});
table.Tr(attr => builder.Field<Text>(f => f.Model).ColSpan(3).Build());
table.Tr(attr => builder.Field<RadioList>(f => f.TaxRate).ColSpan(3).Set(f => f.Items, AppDictionary.TaxRates).Build());//单选按钮
table.Tr(attr =>
{
builder.Field<Number>(f => f.MinStock).Build();//数值框
builder.Field<Number>(f => f.MaxStock).Build();
});
table.Tr(attr => builder.Field<TextArea>(f => f.Note).ColSpan(3).Build());//文本域
});
}
//表单底部按钮
protected override void BuildButtons(RenderTreeBuilder builder)
{
builder.Button(FormButton.Save, Callback(OnSave), !ReadOnly);
base.BuildButtons(builder);
}
//保存按钮方法
private void OnSave() => SubmitAsync(Client.Goods.SaveGoodsAsync);
}
3. 后端
3.1. 创建Controller类
- 在KIMS.Core项目Controllers文件夹下创建GoodsController类
- 该类为服务端WebApi,继承BaseController类
[Route("[controller]")]
public class GoodsController : BaseController
{
private GoodsService Service => new(Context);
[HttpPost("[action]")]
public PagingResult<KmGoods> QueryGoodses([FromBody] PagingCriteria criteria) => Service.QueryGoodses(criteria);
[HttpPost("[action]")]
public Result DeleteGoodses([FromBody] List<KmGoods> models) => Service.DeleteGoodses(models);
[HttpPost("[action]")]
public Result SaveGoods([FromBody] object model) => Service.SaveGoods(GetDynamicModel(model));//转成dynamic类型
}
3.2. 创建Service类
- 在KIMS.Core项目Services文件夹下创建GoodsService类
- 该类为业务逻辑服务类,继承ServiceBase类
class GoodsService : ServiceBase
{
internal GoodsService(Context context) : base(context) { }
//分页查询
internal PagingResult<KmGoods> QueryGoodses(PagingCriteria criteria)
{
return GoodsRepository.QueryGoodses(Database, criteria);
}
//删除数据
internal Result DeleteGoodses(List<KmGoods> models)
{
if (models == null || models.Count == 0)
return Result.Error(Language.SelectOneAtLeast);
//此处增加删除数据校验
return Database.Transaction(Language.Delete, db =>
{
foreach (var item in models)
{
db.Delete(item);
}
});
}
//保存数据
internal Result SaveGoods(dynamic model)
{
var entity = Database.QueryById<KmGoods>((string)model.Id);
entity ??= new KmGoods { CompNo = CurrentUser.CompNo };
entity.FillModel(model);
var vr = entity.Validate();
if (vr.IsValid)
{
if (GoodsRepository.ExistsGoods(Database, entity))
return Result.Error("商品编码已存在。");
}
if (!vr.IsValid)
return vr;
return Database.Transaction(Language.Save, db =>
{
if (entity.IsNew)
{
entity.Code = GetGoodsMaxNo(db);
}
db.Save(entity);
}, entity.Id);
}
//获取商品最大编码
private static string GetGoodsMaxNo(Database db)
{
var prefix = "G";
var maxNo = GoodsRepository.GetGoodsMaxNo(db, prefix);
if (string.IsNullOrWhiteSpace(maxNo))
maxNo = $"{prefix}0000";
return GetMaxFormNo(prefix, maxNo);
}
}
3.3. 创建Repository类
- 在KIMS.Core项目Repositories文件夹下创建GoodsRepository类
- 该类为数据访问类
class GoodsRepository
{
//分页查询
internal static PagingResult<KmGoods> QueryGoodses(Database db, PagingCriteria criteria)
{
var sql = "select * from KmGoods where CompNo=@CompNo";
return db.QueryPage<KmGoods>(sql, criteria);//查询条件自动绑定
}
//获取商品最大编码
internal static string GetGoodsMaxNo(Database db, string prefix)
{
var sql = $"select max(Code) from KmGoods where CompNo=@CompNo and Code like '{prefix}%'";
return db.Scalar<string>(sql, new { db.User.CompNo });
}
//判断商品是否已存在
internal static bool ExistsGoods(Database db, KmGoods entity)
{
var sql = "select count(*) from KmGoods where Id<>@Id and Code=@Code";
return db.Scalar<int>(sql, new { entity.Id, entity.Code }) > 0;
}
}
3.4. 创建Import类
- 在KIMS.Core项目Imports文件夹下创建KmGoodsImport类(约定:类名以实体类名+Import)
- 该类为数据异步导入处理类,由框架自动调用,继承BaseImport类
class KmGoodsImport : BaseImport
{
public KmGoodsImport(Database database) : base(database) { }
//定义导入栏位,自动生成导入规范
public override List<ImportColumn> Columns
{
get
{
return new List<ImportColumn>
{
new ImportColumn("商品类型", true),
new ImportColumn("商品编码", true),
new ImportColumn("商品名称", true),
new ImportColumn("计量单位", true),
new ImportColumn("规格型号", true),
new ImportColumn("税率"),
new ImportColumn("库存下限"),
new ImportColumn("库存上限"),
new ImportColumn("备注")
};
}
}
//异步导入处理逻辑
public override Result Execute(SysFile file)
{
var models = new List<KmGoods>();
var result = ImportHelper.ReadFile(file, row =>
{
var model = new KmGoods
{
CompNo = file.CompNo,
Type = row.GetValue("商品类型"),
Code = row.GetValue("商品编码"),
Name = row.GetValue("商品名称"),
Unit = row.GetValue("计量单位"),
Model = row.GetValue("规格型号"),
TaxRate = row.GetValue<decimal?>("税率"),
MinStock = row.GetValue<decimal?>("库存下限"),
MaxStock = row.GetValue<decimal?>("库存上限"),
Note = row.GetValue("备注")
};
var vr = model.Validate();
if (vr.IsValid)
{
if (models.Exists(m => m.Code == model.Code))
vr.AddError("商品编码不能重复!");
else if (GoodsRepository.ExistsGoods(Database, model))
vr.AddError($"系统已经存在该商品编码!");
}
if (!vr.IsValid)
row.ErrorMessage = vr.Message;
else
models.Add(model);
});
if (!result.IsValid)
return result;
return Database.Transaction("导入", db =>
{
foreach (var item in models)
{
db.Save(item);
}
});
}
}
4. 运行测试
- 运行效果如下


5. 相关资料
Blazor实战——Known框架增删改查导的更多相关文章
- 【讲义提纲】以一个实战新闻cms增删改查demo为例,给学院国创队伍培训php
PHP实战基础——以一个新闻cms的增删改查为例 一. 环境配置 二. 数据库创建 三. 增删改查demo 连接数据库 <?php $link=mysq ...
- jeesite应用实战(数据增删改查),认真读完后10分钟就能开发一个模块
jeesite配置指南(官方文档有坑,我把坑填了!)这篇文章里,我主要把jeesite官方给出的帮助文档的坑填了,按照里面的方法可以搭建起来jeesite的站点.系统可以运行以后,就可以进入开发模块了 ...
- Laravel框架——增删改查
增: //save返回true false $res = new member(); res->username = 'a'; $res->password = 'b'; dd($res- ...
- yii2框架增删改查案例
//解除绑定蓝牙 //http://www.520m.com.cn/api/pet/remove-binding?healthy_id=72&pet_id=100477&access- ...
- Hibernate框架增删改查测试类归为一个类
package cn.happy.test; import org.hibernate.Session; import org.hibernate.SessionFactory; import org ...
- Hibernate框架增删改查
package cn.happy.util; import org.hibernate.Session; import org.hibernate.SessionFactory; import org ...
- YII框架增删改查常用语句
//实例化db $db = new \yii\db\Query(); //插入 $db->createCommand()->insert('user', [ 'name' => 't ...
- idea+Maven+SSM框架增删改查
完整项目结构 1.maven配置文件pom.xml <?xml version="1.0" encoding="UTF-8"?> <!-- L ...
- Mybatis框架增删改查
一.recourses中核心配置文件mybatis-config.xml 二. recourse中jdbc.properties 三.entity实体类 四.ISmbmsUserDao层 五.ISmb ...
- MyBatis框架,增删改查
一.recourses中核心配置文件mybatis-config.xml 二. recourse中jdbc.properties 三.entity实体类 四.Dao层 五.ISmbmsUserDao. ...
随机推荐
- MySQL学习(三)DQL/DML/DDL/DCL 介绍
参考博客:https://blog.csdn.net/tomatofly/article/details/5949070 DQL(data query language) :数据查询语言 select ...
- 【读书笔记】组合计数中的行列式方法 专题2 欧拉回路,the BEST theorem
目录 专题2-欧拉回路,the BEST theorem 一些定义 一个有向图是欧拉的充要条件 BEST定理 BSET定理推论 k-ary de Bruijn sequence定义 BSET theo ...
- fluter usage---->动态更换Theme
应用中切换深色主题和暗色主题是比较常见的操作,今天我们就来学习一下Flutter中动态的切换主题. Simple Theme import 'package:flutter/material.dart ...
- VUE-生命周期/请求数据
使用方法 --- 4个before,4个ed,创造,装载,更新,销毁 初始化阶段 beforeCreate(){} // 准备怀孕 created(){} // 怀上了 *************** ...
- .net core基于HttpClient实现的网络请求库
Soda.Http 基于HttpClient封装的 Http 请求库.如果有什么好想法,可以提 Issue 或者 Pr.,如果想要使用,直接在nuget搜索Soda.Http即可. Github项目地 ...
- 读破万卷,神交古人,突破ChatGPT4096的Token限制,建立自己的垂直领域资料人工智能助理
ChatGPT的泛用性极高,上知天文,下通地理,参考古今,博稽中外,几乎无所不知,无所不晓.但如果涉及垂直领域的专业知识点,ChatGPT难免也会有语焉不详,闪烁其词的毛病,本次我们将特定领域的学习材 ...
- 基于Label studio实现UIE信息抽取智能标注方案,提升标注效率!
基于Label studio实现UIE信息抽取智能标注方案,提升标注效率! 项目链接见文末 人工标注的缺点主要有以下几点: 产能低:人工标注需要大量的人力物力投入,且标注速度慢,产能低,无法满足大规模 ...
- c++实战开发程序
非常感谢您的进一步提问,以下是一个对于实战开发小程序的更具体的建议: 第1周实战开发小程序建议:写一个简单的计算器程序,要求包含加.减.乘.除四种基本运算,并进行错误处理,例如输入了非法字符或者除数为 ...
- 1 Android开发书籍
不管你是Android菜鸟还是Android高手,一定能够找到一本适合自己阅读的书籍.下面为大家推荐8本书. <Android进阶之光> <Android进阶之光>详细并深入讲 ...
- flask-wtfwkfom使用
我们在使用flask框架来搭建自己的博客,只要是设涉及到表单相关,必然会想起Flask-WTF与WTForms.对于flask初学者来说,比较容易混淆两者.今天想来一一解释两者的用法. Flask-W ...