近日,客户在使用软件过程中反映,在添加一条新客户记录后,存盘时,系统给出一个“系统无法处理的异常”的错误提示,无法保存该条记录。
  根据客户的反馈,经过长达数小时的跟踪和确认,终于将问题定位在OleDataAdapter的Update()方法上,并得到Debug提示“违反并发性: UpdateCommand 影响了预期 1 条记录中的 0 条”。
  并且,该问题仅出现在下列情况中:
  1.登录后,只添加一条空记录(而不是连续添加多条空记录,然后再一一修改),发现记录编号从0开始;
  2.经过查询操作,查到一个空表(没有查到任何满足条件的记录),然后立刻添加一条新记录,发现记录编号从0开始;

  上网搜索到一些解决办法,但无一奏效。基本上搜索结果定位为下列三点:

  1 检查是否设有主键。
  2 DeleteCommand的问题:检查是否含有自动编号字段(Access的自动编号字段可能会引发此异常);
  3 UpdateCommand的问题:检查更新的字段的原始值是否为空值(原始空值更新时可能会引发此异常)。

  首先,我的后台数据库客户信息表的确设置了主键,因此排除1;
  其次,客户需求说明中并无删除功能,因此DeleteCommand对象行同虚设,从未被调用过,因此排除2,可是,对自动编号的解释比较符合我的猜测;
  最后一条,关于空值的解释,由于我是用了混合编码,数据库DataSet对象是IDE自动产生的,已经充分屏蔽掉了该问题,所以,也不太符合现有程序的出错条件。

  终于,在跟踪UpdateCommand过程中,确定该问题出在UpdateCommand的CommandText属性上,该属性经过替换参数后,WHERE条件为 ID = 0 。查看数据库的客户信息表,ID字段为自动编号字段,但并没有指定种子编号的数字(Access中未找到指定该数值的设置),并且,实际编号是从1开始的。到此,终于确定了问题的真正原因:
  我在添加一条记录的时候,首先存储了这条空记录,而这条空记录的真实编号(ID)一定是大于0的,在数据表格中出现的编号却每次都从0开始(在上述2中报错的情况),在编程实现自动化替换过程中,将UpdateCommand命令的编号替换成了0,造成提交时更新操作失败(根本不存在编号为0的记录),Debug提示:“违反并发性: UpdateCommand 影响了预期 1 条记录中的 0 条”。
  找到了问题的原因,开始着手解决:
  首先,考虑如何找到真实的记录编号。根据数据库中的编号与表格中编号不一致,可以推断,表格控件会自动按自己的初始设置,为新增加的记录分配记录编号,并且,该记录编号没有在提交添加记录事务后,与数据库的记录编号进行同步。那么,下面就是找到这个初始设置(编号种子),在每次添加新记录之前,人工来做新记录编号分配工作(同步记录编号)。在系统自动生成的DataSet的客户信息表(DataTable)下面,“编号Column”对象的属性 AutoIncrementSeed就是用来设置该编号种子的,该属性初值被设置为0,这正是前面两种添加记录的情况所导致的问题的根源。
  
  接下来,创建一个GetNewID方法,该方法在每次添加操作之前,取得数据库“客户信息表”的最大编号,然后增加1,并将该值设置到 DataTable的“编号Column”对象的AutoIncrementSeed属性。这样,每次添加之前,系统都回取到最新的编号,存盘后,系统自动存储到数据库的编号自然与取到的编号是同步更新的,就不会出现“违反并发性”的错误了。

  为了搞清如此简单的问题,我付出了6个小时的代价,其中,被强力折磨4个小时。不过,还是非常值得的,因为,网络上居然没找到一个能将该问题解答清楚的,他奶奶的!

后记:我也在开发过程中遇到了这个问题,试着用文章中的方法解决未遂,后来一气之下删除自动编号字段,另用其它字段为主键手工生成ID,终于解决该问题,浪费了很多时间