• 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
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    1.2. 创建Client类

    • 在KIMS项目Clients文件夹下创建GoodsClient类
    • 该类是前后端数据交互接口,继承BaseClient类
    • 该类只需提供分页查询、删除和保存,导入功能由框架统一异步处理
    public class GoodsClient : ClientBase
    {
        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);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    2. 前端

    2.1. 创建List页面

    • 在KIMS.Razor项目BaseData文件夹下创建GoodsList类
    • 该类是数据列表页面,继承WebGridView
    • 列表页面按钮和栏位在框架模块管理中配置
    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() => DeleteRows(Client.Goods.DeleteGoodsesAsync);//批量删除按钮方法
        public void Edit(KmGoods row) => ShowForm(row);//编辑操作方法
        public void Delete(KmGoods row) => DeleteRow(row, Client.Goods.DeleteGoodsesAsync);//删除操作方法
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    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 =>
                {
                    table.Field<Text>(f => f.Code).Enabled(TModel.IsNew).Build();//编码,编辑时灰显
                    table.Field<Text>(f => f.Name).Build();
                });
                table.Tr(attr =>
                {
                    table.Field<Select>(f => f.Type).Set(f => f.Codes, AppDictionary.GoodsType).Build();//下拉框
                    table.Field<Select>(f => f.Unit).Set(f => f.Codes, AppDictionary.GoodsUnit).Build();
                });
                table.Tr(attr => table.Field<Text>(f => f.Model).ColSpan(3).Build());
                table.Tr(attr => table.Field<RadioList>(f => f.TaxRate).ColSpan(3).Set(f => f.Items, AppDictionary.TaxRates).Build());//单选按钮
                table.Tr(attr =>
                {
                    table.Field<Number>(f => f.MinStock).Build();//数值框
                    table.Field<Number>(f => f.MaxStock).Build();
                });
                table.Tr(attr => table.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);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39

    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类型
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    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);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58

    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;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    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);
                }
            });
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68

    4. 运行测试

    • 运行效果如下
      在这里插入图片描述
      在这里插入图片描述

    5. 相关资料

  • 相关阅读:
    驱动开发:内核监控FileObject文件回调
    mac 和 windows 相互传输文件【共享文件夹】
    MySQL高级篇03【逻辑架构】
    PLSQL数据库Mybatis学习Day02
    如何在Win系统部署Tomcat服务并实现远程访问内网站点
    QT_day6
    Spring依赖注入、循环依赖——三级缓存
    [2022-11-13]神经网络与深度学习 hw8 -RNN造轮子篇
    IAR For ARM 安装教程
    基于JAVA爱馨敬老院网站计算机毕业设计源码+系统+lw文档+部署
  • 原文地址:https://blog.csdn.net/knownchen/article/details/130859287