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

Posted KNOWN

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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 = $"prefix0000";
        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. 相关资料

jeesite应用实战(数据增删改查)

jeesite配置指南(官方文档有坑,我把坑填了!)这篇文章里,我主要把jeesite官方给出的帮助文档的坑填了,按照里面的方法可以搭建起来jeesite的站点。系统可以运行以后,就可以进入开发模块了,我们先从数据的增删改查做起。

一、页面效果

技术分享图片

很简单,涉及到的就是数据的增删改查。

二、如何利用jeesite做呢?

上面我们也看到了,功能很简单,那么怎么利用jeesite做呢?jeesite能给我们提供什么便利呢?

第一步、建表

利用jeesite之前,要先建数据表。

技术分享图片

至于怎么建表,方法太多了,怎么建都行,但是图中标出的红色部分的字段为必须字段,jeesite要用。

第二步、利用jeesite生成代码

1.点击【代码生成】,点击【业务表配置】,点击【业务表添加】

技术分享图片

选中第一步中创建的表后,点击【下一步】,这个表已经添加过了,所以失败了。

技术分享图片

如果成功的话,是这样的界面。

技术分享图片

点击【保存】,可以看到如下信息。

技术分享图片

然后,我们点击【生成方案配置】,点击【添加】,填写对应的信息,如下。

技术分享图片

注意: 
1. 模板分类要选择“增删改查(单表)”。 
1. 生成的模块名为设定好的模块名,如esi为电商资讯模块名(约定俗成好的) 
2. 选择对应的业务表名,如esi_elec_dynamic表。 
3. 如果以前已经生成过了,现在要替换,那么就勾选上【是否替换现有文件】的复选框。 
4. jeesite在Mac系统下无法生成代码,所以这一步要在Windows下完成。点击【保存并生成代码】生成完后,jeesite会提示生成的路径,包含了webcontent目录下和src目录下的文件夹。

第二步、复制代码到工作库

关键,根据jeesite提示的路径找到文件夹后,将对应的文件夹放在对的目录下,一定要正确。

技术分享图片

技术分享图片

第三步、新建菜单

点击【系统设置】-》【菜单管理】-》【菜单添加】。

技术分享图片

添加完横向导航条的菜单后,继续添加菜单,分别如下图。

技术分享图片

技术分享图片

链接的文本框怎么填呢?

技术分享图片

和@RequestMapping相呼应。

权限标识呢?

和该EsiElecDynamicController.java类中的@RequiresPermissions相呼应。

技术分享图片

第四步、新建字典

技术分享图片

注意排序和键值。

第五步、分配角色

技术分享图片

例子中只是对admin用户添加了行业动态的权限。可自行配置。

第六步、字典应用

技术分享图片

添加动态的时候,可以看到有选项,分别为发布和审核,这个时候就需要应用字典数据了。

esiElecDynamicForm.jsp代码片段

<shiro:hasPermission name="cms:article:audit">
    <div class="control-group">
        <label class="control-label">发布状态:</label>
        <div class="controls">
            <form:radiobuttons path="delFlag" items="${fns:getDictList(‘esi_audit_status‘)}" itemLabel="label" itemValue="value" htmlEscape="false" class="required"/>
            <span class="help-inline"></span>
        </div>
    </div>
</shiro:hasPermission>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

最外层的是权限设置,注意form:radiobuttons path="delFlag" items="${fns:getDictList(‘esi_audit_status‘)}"

  1. path的值对应的是EsiElecDynamic.java类中的字段。
  2. items就是从字典中取出的值了。

第七步、显示发布人

技术分享图片

显示发布人,需要关联到几个地方,一定要注意。

第一处,esiElecDynamicList.jsp

<td>${esiElecDynamic.user.name}</td>
  • 1

第二处,EsiElecDynamic.java

private User user;
public User getUser() {
    return user;
}

public void setUser(User user) {
    this.user = user;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

第三处,EsiElecDynamicDao.xml

<sql id="esiElecDynamicColumns">
    a.id AS "id",
    a.title AS "title",
    a.content AS "content",
    a.files AS "files",
    a.create_by AS "createBy.id",
    a.create_date AS "createDate",
    a.update_by AS "updateBy.id",
    a.update_date AS "updateDate",
    a.remarks AS "remarks",
    a.del_flag AS "delFlag",
    u.name AS "user.name"
</sql>

<sql id="esiElecDynamicJoins">
    JOIN sys_user u ON u.id = a.create_by
</sql>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

第八步、设置列宽

技术分享图片

esiElecDynamicList.jsp

<th>标题</th>
<th width="30%">发布内容</th>
<th>发布者</th>
<th width="20%">发布时间</th>
<shiro:hasPermission name="esi:esiElecDynamic:edit">
    <th>操作</th>
</shiro:hasPermission>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

第九步、增加状态的选择查询

技术分享图片

当点击发布、审核单选按钮的时候,我们希望页面能自动查询,怎么做呢?

esiElecDynamicList.jsp

<li><label>状态:</label> <form:radiobuttons onclick="$(‘#searchForm‘).submit();" path="delFlag"
                    items="${fns:getDictList(‘esi_audit_status‘)}" itemLabel="label" itemValue="value" htmlEscape="false" /></li>
  • 1
  • 2
  1. path=”delFlag”会关联到数据库中的del_flag字段。
  2. onclick时提交表单。

 






以上是关于Blazor实战——Known框架增删改查导的主要内容,如果未能解决你的问题,请参考以下文章

SpringMVC学习记录----SSM 框架实战 用户信息增删改查

基于C#和Blazor开发的前后端分离框架

ElasticSearch实战(十七)-增删改查

jeesite应用实战(数据增删改查)

ElasticSearch实战(十七)-DSL增删改查

如何用SSM框架写一个增删改查的功能