.net的这经典bug
最近在做项目时,发现.net对自动编号的表多条数据进行更新时有个严重bug,导致项目几乎要重做。
1、先建这样一个表
create table tb(id int identity primary key,
value char(10));
2、用.net ide的服务器资源管理器将这个表拖到窗体上,讲设计器生成的连接命名为con,数据适配器命名为sda,然后右击适配器,将生成的类型化数据集命名为ds
3、在窗体上添加添加一个按钮button1,按钮的代码如下:
try
{
ds1.clear();
for (int i=0;i<30;i++)
{
ds.tbrow r=ds1.tb.newtbrow();
r.beginedit();
r.value="aaa";
r.endedit();
ds1.tb.addtbrow(r);
}
con.open();
}
sda.update(ds1.tb);
messagebox.show("ok");
}
catch(system.exception ex)
{
messagebox.show(ex.message);
}
finally
{
con.close();
}
4、运行代码,会产生这样的错误
列"id"被约束为唯一的,值1已存在
5、有时候这种现象会消失,但是如果新建一个表,一定会重复出现。而且最可怕的是,这种现象会不规则的出现。
6、以下sql代码可以重建这个表
drop table tb;
create table tb(id int identity primary key,
value char(10));
select count(*) from tb
7、如果自己用windows生成的sql命令,则可以更新数据,但是会引起删除时的并发错误问题。
try
{
ds1.clear();
for (int i=0;i<30;i++)
{
ds.tbrow r=ds1.tb.newtbrow();
r.beginedit();
r.value="aaa";
r.endedit();
ds1.tb.addtbrow(r);
}
con.open();
for(int i=0;i<ds1.tb.count;i++)
{
sda.insertcommand.parameters["@value"].value=ds1.tb[i].value;
sda.insertcommand.executenonquery();
} messagebox.show("ok");
}
catch(system.exception ex)
{
messagebox.show(ex.message);
}
finally
{
con.close();
}
大家有兴趣可以讨论一下,看有没有办法解决这个大型bug
推荐阅读
如果确认是bug,最好反馈到微软,希望能使.net更完善
原来如此,前面说的可能不是很对.
呵呵,都是个人理解.:)
我追踪一下每条记录的insert过程
问题并不是出在sql语句上.
问题出在datatable上
确实是偶尔发生
这个问题是这样的:
因为在datatable中定义了主键,就是id
在新建行的时候它没有被手工赋值.
于是自动产生一个数字.
正如我所说.dataset是脱机操作.并不能知道数据源的目前id
可能会被赋值为如下序列:0,1,2,3,4
在更新第0条的时候.数据成功了,但是@@identity 是1 因为数据库中是从1 开始的
于是自动update要更新第1条数据(id 为 0 这条)
datatable的id被设为主键.不能重复.于是datatable不能更新这单条记录
与第二条的id重复(这条的id还是1,如果它被insert就会变成2,但是还没有,所以报错)
这个错误不是数据库中的错误
是datatable本地错误.无法同时允许两个相同id(所有行都update完不会有这种情况)
过程如下 (数据库从1 开始,这里是说的datatable中的id)
0,1,2,3,4 初始状态
1,1,2,3,4 更新第一条报错 有两个1
1,2,2,3,4 如此循环下去......但是前面就抛出异常了
楼主所说的偶尔发生是这种情况
datatable中的id是 100,101,102,103
数据库中是从1开始的.
过程就是:
1,101,102,103 更新第一条
1,2,102,103 更新第二条
1,2,3,103 更新第三条
1,2,3,4 更新第四条
这样更新到最后也不会出错
我也不能说这是不是bug了.呵呵.但问题就是这样
解决办法就是把生的数据集中 对自增序列的pk去掉
允许在datatable中某时刻有重复id(只是瞬间,呵呵)
一般自增序列是由数据库维护的.不能编辑,定义它为pk没有什么意思.因为必不会重复
建议pk就加在别的字段上面吧.
建議把數據操作(insert,update,delete)寫成自己的方法,讓用戶傳入值,你在方法里面拼裝成sql語句,然后送到數據庫執行之。這樣就不會有什么問題,而且效率也不錯。當然注意數據的操作基本都是在內存中,到提交時候才訪問數據庫。
.

讨论区