经常回顾同事写的代码,发现一些问题,总结分析,用于员工培训,或系统优化方面的内容教学。

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

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;
}
}

.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }

从代码的意图中我们可以看出,这是一个需要用户确认的操作。当用户勾选单选框之后,读取数据判断是否合理,提示用户之后将单选框取消选择。在这里,我们完全可以把操作放到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);

.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }

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

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

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

ERP程序开发中遇到的六种错误的更多相关文章

  1. 在C#/.NET应用程序开发中创建一个基于Topshelf的应用程序守护进程(服务)

    本文首发于:码友网--一个专注.NET/.NET Core开发的编程爱好者社区. 文章目录 C#/.NET基于Topshelf创建Windows服务的系列文章目录: C#/.NET基于Topshelf ...

  2. 总结微信小程序开发中遇到的坑

    总结微信小程序开发中遇到的坑,一些坑你得一个一个的跳啊,/(ㄒoㄒ)/~~ 1,页面跳转和参数传递实例 首先说一下我遇到的需求有一个我的消息页面,里面的数据都是后端返回的,返回的数据大致如下,有一个是 ...

  3. IOS程序开发中-跳转到 发送短信界面 实现发短信

    前言:我发现我标题取的不好,谁帮我取个承接上下文的标题?评论一下,我改 项目需求:在程序开发中,我们需要在某个程序里面发送一些短信验证(不是接收短信验证,关于短信验证,传送门:http://www.c ...

  4. 微信小程序开发教程 #043 - 在小程序开发中使用 npm

    本文介绍了如何在微信小程序开发中使用 npm 中包的功能,大大提高微信小程序的开发效率,同时也是微信小程序系列教程的视频版更新. 微信小程序在发布之初没有对 npm 的支持功能,这也是目前很多前端开发 ...

  5. AOP称为面向切面编程,在程序开发中主要用来解决一些系统层面上的问题

    AOP称为面向切面编程,在程序开发中主要用来解决一些系统层面上的问题,比如日志,事务,权限等待,Struts2的拦截器设计就是基于AOP的思想,是个比较经典的例子. 一 AOP的基本概念 (1)Asp ...

  6. 解决微信小程序开发中wxss中不能用本地图片

    微信小程序开发中wxss中不能用本地图片,我们可以用将我们的图片传到服务器上,然后直接引用在线地址.但是当我们没有服务器时,我们可以用"图床",这个具体可以百度.这里我们用第二种方 ...

  7. 程序开发中的术语,如IDE,OOP等等

    我们在开发程序过程中,会用到一些与编译有关的术语,比如:[编辑器.编译器.调试器.连接器,链接器.解释器,集成开发环境(Integrated Development Environment,IDE). ...

  8. Python基础教程(011)--程序开发中的错误及原因

    前言 排查代码开发中的错误 内容 1,编写的程序不能正常执行,或者执行的结果不是我们期望的 2,俗称bug,是程序开发常见的,初学常见的原因有 手误 对已经学习的知识点理解不足 对语音还有需要学习和提 ...

  9. 读书笔记-详解C程序开发中 .c和.h文件的区别

    一个简单的问题:.c和.h文件的区别 学了几个月的C语言,反而觉得越来越不懂了.同样是子程序,可以定义在.c文件中,也可以定义在.h文件中,那这两个文件到底在用法上有什么区别呢? 2楼: 子程序不要定 ...

随机推荐

  1. 一百元的智能家居——Asp.Net Mvc Api+讯飞语音+Android+Arduino

    大半夜的,先说些废话提提神 如今智能家居已经不再停留在概念阶段,高大上的科技公司都已经推出了自己的部分或全套的智能家居解决方案,不过就目前的现状而言,大多还停留在展厅阶段,还没有广泛的推广起来,有人说 ...

  2. Centos6.5下编译安装mysql 5.6

    一:卸载旧版本 使用下面的命令检查是否安装有MySQL Server rpm -qa | grep mysql 有的话通过下面的命令来卸载掉 rpm -e mysql //普通删除模式 rpm -e ...

  3. Webpack 配置摘要

    open-browser-webpack-plugin 自动打开浏览器 html-webpack-plugin 通过 JS 生成 HTML webpack.optimize.UglifyJsPlugi ...

  4. win8.1硬盘安装ubuntu14.04双系统

    在网上找了很多方法都失败了,原因是大多数方法都是用mbr方式安装的,如grub4dos,easybcd.以至于连自己都怀疑win8能不能用硬盘安装,差点就去买个u盘来安装了,就在打算放弃的时候在ubu ...

  5. 前端HTML5几种存储方式的总结

    接下来要好好总结一些知识,秋招来啦...虽然有好多知识都不大会,但是还是要努力一下,运气这种东西,谁知道呢~ 总体情况 h5之前,存储主要是用cookies.cookies缺点有在请求头上带着数据,大 ...

  6. 【NLP】十分钟快览自然语言处理学习总结

    十分钟学习自然语言处理概述 作者:白宁超 2016年9月23日00:24:12 摘要:近来自然语言处理行业发展朝气蓬勃,市场应用广泛.笔者学习以来写了不少文章,文章深度层次不一,今天因为某种需要,将文 ...

  7. NPM如何更新到最新版

    参考文章--npm更新到最新版本的方法 其实我们可以这样,随便新建一个文件夹例如:F:\test.按着"shift"键,右键该文件夹,选择"在此处打开命令窗口(W)&qu ...

  8. 微信小程序二维码推广统计

    微信小程序可以通过生成带参数的二维码,那么这个参数是可以通过APP的页面进行监控的 这样就可以统计每个二维码的推广效果. 今天由好推二维码推出的小程序统计工具HotApp小程序统计也推出了带参数二维码 ...

  9. gulp 自动添加版本号

    本文介绍利用 gulp-rev 和 gulp-rev-collector 进行版本管理 npm官网介绍使用后的效果如下: "/css/style.css" => " ...

  10. Linux实战教学笔记03:操作系统发展历程及系统版本选择

    标签(空格分隔): Linux实战教学笔记-陈思齐 第1章 Linux简介 1.1 什么是操作系统? 简单讲:操作系统就是一个人与计算机硬件的中介. 操作系统,英文名称Operating System ...