• ERP程序开发中遇到的六种错误
  • 经常回顾同事写的代码,发现一些问题,总结分析,用于员工培训,或系统优化方面的内容教学。

    文中有问题的的代码我用黑体字标识。

    1 界面与逻辑代码混淆

    这是目前发现的比较严重的问题。框架花费了很大的力气,运用数据绑定,就是为了让界面(控件操作)与后台逻辑(验证与传值)执行相对严格的分离。这里我只能说相对严格的分离,因为后台中一些操作不可避免的需要在前台提示用户确认,或是提示用户输入一些变量值,这部分逻辑也可能会参与在前台界面中。我举例如下。

    private void grid_AfterCellUpdate(object sender, CellEventArgs e)
    {         
                if (this.gridUom.ActiveCell == null || !this.gridUom.ActiveCell.IsDataCell)
                    return;
    
                ItemEntity Ientity = itemBindingSource.Current as ItemEntity;
                ItemAuxiLiaryEntity itemAuxiLiaryEntity = gridUom.GetRowListObject(gridUom.ActiveRow) as ItemAuxiLiaryEntity;
                if (gridUom.ActiveRow != null)
                {
                    if (BaseCommon.StringCompare(e.Cell.Column.Key, "AuxiLiaryDefault") == 0)
                    {
                       
                        List<int> indices = entity.ItemAuxiLiaries.FindMatches(ItemAuxiLiaryFields.AuxiLiaryDefault == true & ItemAuxiLiaryFields.Uom != itemAuxiLiaryEntity.Uom);
                        if (indices.Count > 0)
                        {
                            ItemAuxiLiaryEntity customerEntity = entity.ItemAuxiLiaries[indices[0]] as ItemAuxiLiaryEntity;
                            customerEntity.AuxiLiaryDefault = false;
                         }
                 }
    }
    

    这段代码有以下几个问题

    1 AfterCellUpdate事件完全可以放到后台业务逻辑类中,因为这里只是做业务操作操作,并不涉及到用户确认或输入数据或用户通知的行为,可以归纳的说,除了这三种特殊类型的操作之外(用户确认,输入数据,用户通知)的数据变更,都可以放置到后台业务实体中完成。

    2 性能:这里经过了多次数据转化调用(as操作符),它的性能不太好。而且列名的判断太迟,每次对Grid的单元格的操作都会触发两次数据转化(as操作符)行为。

    这类XX_Changed,XX_Updated,尽量将代码迁移到后台逻辑中。一是为了维护,二是改善性能。

    2  事件的不恰当运用

    Closing事件是正在关闭时发生,还没有关闭,这时可以取消,阻止事件冒泡。Closed是关闭完成,可以做一些其它的资源释放操作。理解这两个事件的区别,有助于合理应用事件。参考下面的代码

    private void chbSuspended_CheckedChanged(object sender, EventArgs e)
     {
                if (chbSuspended.Checked)
                {
                    if (!string.IsNullOrEmpty(txtItemNo.Text))
                    {
                       
                        IPurchaseOrderManager PurchaseOrderManager = ClientProxyFactory.CreateProxyInstance<IPurchaseOrderManager>();
                        if (PurchaseOrderManager.IsPurchaseOrderExist(bucket))
                        {
                            DialogResult Result = BaseCommon.ShowConfirm("Item is already in used", null, MessageBoxButtons.OKCancel);
                            if (Result != DialogResult.OK)
                            {
                                chbSuspended.Checked = false;
                            }
                        }
    从代码的意图中我们可以看出,这是一个需要用户确认的操作。当用户勾选单选框之后,读取数据判断是否合理,提示用户之后将单选框取消选择。在这里,我们完全可以把操作放到Validating事件或是Changing事件中,表达这个值改变之前还需要我们的验证确认,这样对系统的性能开销比较小。如果如上代码所示,等到值改变完成,控件刷新完成之后,再把它还原到未改变之前的状态,这样的性能不好。
     

    3 应该考虑用空间换时间的性能改善方案

    简单的说,就是把值提前计算好并保存起来,在用的时候直接读取值以取代频繁的计算。这种情况出现的几率对高,我做几处说明。
    1)主表与从表的关系数据。主表需要保存从表的数据统计。比如销售订单表头有一个Amount金额字段用于保存明细行的金额累总,这就是一个典型的空间换时间的方案。因为读取表头的字段发生的频率太高了,所以我们不会每次都读取明细行并累总显示。
    2)基础数据表与业务表的数据。比如,我要统计某一个商品的采购订单数量累总,销售订单数量累总,生产任务单数量累总。我们常用的方法是,要用到这些累总时,直接去读取单据数据。而我这里推荐的是空间换时间的方案。做单据业务时,将业务单据的数据提前保存到基础数据表中。再具体来说,就是qty_on_order(商品销售订单数量),qty_on_jo(商品生产订单数量)等累总字段增加到物料表中,在做业务单据时更新物料表相应字段的值。
    3)业务数据表的分析表。比如我们销售送货单,会创建两张表(Shipment/ShipmentDetail)记录此数据。为此,我们还需要提供大量的查询以满足各种业务场景。这时就可以考虑将创建新的数据表来存储相关的查询结果,比如未送货/未完成订单,需要综合订单表或送货表来多纬度的查询,按客户,按销售员,按项目等。这个项目中,会产生比较多的Balance,Journal,Summary等数据表。
     

    4 合理利用缓存可改善系统效率

    对于一些不常改变的数据项,在实施阶段就固定下来的基础数据,我们可以考虑在系统登入前缓存到系统数据字典中,这样在读取数据时可显示改善效率。一些常有的基础数据,比如单位,货币,销售员,会计帐户,考虑将它们加入到系统缓存中。如用户更改这些数据项,需要更新缓存中的数据项。
    缺少了这项考虑,系统就会出现频繁的从各个基础数据表中读取数据,给系统的效率带来负担。

     

    5 缺少对数据库NULL值的处理

    对于数量单价类的字段值,它是直接从用户界面中获取,而对于平均单价,最后一次进仓单价,它们的值由系统计算得出。这就会造成前者与后者数据的产生时机不一致,两者为空值NULL的情况会比较多。于是下面的查询过滤条件常常是没有作用的。
    IRelationPredicateBucket bucket=...
    bucket.PredicateExpression.Add(SalesOrderDetailFields.Qty > SalesOrderDetailFields.DeliveryQty);

    对于字符串的字段,null和string.Empty是不同的,在数据库中,NULL和空字符串也是不同的。字符的全角半角也应该控制好。

    6 启动窗体时载入数据项过多

    尽量使用延迟加载数据的模式,而避免启动界面时及时加载所有的数据项。这条规则比较明显的地方是界面中有过多的DropDownList或ComboBox。如果确定要使用这类控件,应该将它的数据项载入时间延迟到控件展开时完成(数据绑定优于逐个数据项增加)。参考这里(http://stackoverflow.com/questions/2901371/lazy-loading-wpf-combobox-items)。

  • 相关阅读:
    k8s 部署 custommetricsapiserver 时使用 secret 保存 ca 证书遇到的问题
    ASP.NET Core 获取主机名时的 "Decoded string is not a valid IDN name" 错误
    背水一战 Windows 10 (93) 选取器: FileOpenPicker, FolderPicker, FileSavePicker
    CentOS5/6/7系统下搭建安装Amabari大数据集群时出现SSLError: Failed to connect. Please check openssl library versions.错误的解决办法(图文详解)
    SQL Server 无法生成 FRunCM 线程。请查看 SQL Server 错误日志和 Windows 事件日志
    SQL Server 2017错误日志中出现“Parallel redo is shutdown for database 'xxx' with worker pool size [2]."浅析
    mahout分类学习和遇到的问题总结
    微信小程序开发相关,用uniapp开发同时发布到多个平台上的小程序
    Java避坑宝典《Java业务开发常见错误100例》上线了
    外卖ERP管理系统(一)
  • 【推广】 阿里云小站-上云优惠聚集地(新老客户同享)更有每天限时秒杀!
    【推广】 云服务器低至0.95折 1核2G ECS云服务器8.1元/月
    【推广】 阿里云老用户升级四重礼遇享6.5折限时折扣!
  • 原文地址:https://www.cnblogs.com/JamesLi2015/p/6218771.html
走看看 - 开发者的网上家园