2

Blazor实战——Known框架增删改查导 - known

 1 year ago
source link: https://www.cnblogs.com/known/p/17430085.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

本章介绍学习增、删、改、查、导功能如何实现,下面以商品资料作为示例,该业务栏位如下:

类型、编码、名称、规格、单位、库存下限、库存上限、备注

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.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.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. 相关资料


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK