更新主键产生主键重复问题

cnwin 2012-01-30 07:08:29
这样一种情况,主细表(采购入库单这样)
子表里有行号,行号加表单号(外键)作为联合主键.
正常用没什么问题,现在想实现这样一个功能,用户可能想象用Excel一样插入行,这样就需要将后面的行号重新赋值。这个倒容易。
只不过在adapter.Update时就会有主键重复问题了。一开始还没理解,我的行没有重复的行号啊。
后来想了想,可能更新是一行一行的执行,就像执行以下语句:
"update xxx set line=4 where line=3"
可能是这个原因,也就好解释了,因为数据库里此时确实有行号为4的行阿。
由此想到不只这样,只要有交换主键值的情况都可能出这个问题(只不过一般不会做这种交换的事情)。
目前采用数据绑定的方式,遇到了这样的问题是不是就没法解决了?

我想过如果不采用这种方式,而是手工写代码更新,更新世删除对应表单的所有行,再将现有行插入。应该可以解决。
如果行号不作为主键,也可以解决。只是子表没了唯一值限定,不便使用Adapter自动生成语句。当然可以在另外定义一个自增行号列作为主键来解决(不过该列有可能不是连续的号),保留现有的单据行号。
是不是也就这样解决了?还是有更好的方法?
...全文
1641 31 打赏 收藏 转发到动态 举报
写回复
用AI写文章
31 条回复
切换为时间正序
请发表友善的回复…
发表回复
cnwin 2012-02-09
  • 打赏
  • 举报
回复
是啊,PK是不会重复,可我现在的表结构是单据号加行号为联合主键,试图以不改表结构方式实现这种功能。目前有些进展了。
PaulyJiang 2012-02-08
  • 打赏
  • 举报
回复
PK 插入的时候必定不能重复啊
cnwin 2012-02-08
  • 打赏
  • 举报
回复
测试后结果发现以上方法是有问题的,虽避免了插入行主键重复问题,但删除行则会出现重复。因为删除行后后面的行号要减1,倒序更新就会出现主键重复
“update xxx set line =3 where line=4"
此时line=3的行是存在的所以对于行号减不应倒序。
所以解决方法是将行状态为已删除的记录渠道一个表中先更新,再将行状态为Modified的行取出放到一个表中(DtModify),判断行号原始值小于当前值的记录单独取出来倒序放到一个表中(DtUp),先更新DtModify,在更新DtUp,最后更新行状态为Added的行。
cnwin 2012-02-06
  • 打赏
  • 举报
回复
谢谢楼上对我问题答复的各位朋友。也许觉得我有些钻死牛角尖,大家提出方案来我一直迟迟不肯直接用上,脑子里总不愿意再加主键列,不光是觉得是一个与业务逻辑没关系而称之为“无意义”的列,而是从一种解决升级问题的想法考虑,如何能不更改表结构?所以一直在尝试尽可能的少做更改来解决。

曾在外观层提交要更改的数据表时,试图将要更新的数据表依行号顺序倒序得到新表提交,没实现。就在一筹不展之时,想到Adapter 的Update重载方法有DataRow数组,所以就从数据层下手,重写了更新方法,把更新明细表用dataTable的Select方法按行号倒序排序得到DataRow[],用Adapter Update更新。成功了,解决了主键重复问题,实现了“所输即所得”这种效果。

测试没问题,我想应该不会有大问题吧?各位说说我这种方法有没有问题?
mrsupersky 2012-02-06
  • 打赏
  • 举报
回复
为什么主键都会 产生重复?
这是什么情况啊,不是说 数据库 主键唯一 ,唯一主键 的吗?
不唯一就不适合做主键...
cnwin 2012-02-05
  • 打赏
  • 举报
回复
如果用Guid,那在vs程序中对该DataTable的行指定默认值不太方便。
cnwin 2012-02-05
  • 打赏
  • 举报
回复
谢谢楼上二位的回复。我明白你们的意思,其实我那里说的无意义的主键(列),是说如果我不实现这种插入行,就可以使用表单号加行号做子镳联合主键,这些猎看起来都是必须列。而如果为了实现插入行就不能采用这种联合主键方式,只得另定义个为了主键而主键的列,该列在业务角度来说是无意义的列,在功能角度确实是有重要意义的。
目前我修改了其中的一个表结构,增加一主键列,表单号为外键,已实现了这种功能。只是对主键列采用何种类型有些矛盾。int类型自增列占用为数少,简洁。只是1,2,3,4甚至有时数值可能会不连续,毕竟这数字序列是对该数据库表的一种行序列,这样的简单数字看起来有点别扭,而且有行数超过数据类型范围的那种趋势(实际用起来可能不会出现,仅是趋势而已)。GUID的主键看起来是一串字符,虽读不懂意义,也正是没有明确的意义,反倒让人就把它当作唯一的标识而已,缺点是占用位数长。还没定下来用那种方式。在分布式的应用程序中应采用哪种好呢?
DSIOF3KIDSKTR 2012-02-04
  • 打赏
  • 举报
回复
[Quote=引用 23 楼 qldsrx 的回复:]

你错了,不是添加一个无意义的主键,是有意义的主键。
首先你必须明确一点,主键在插入到数据库后就不能随便修改其值,否则有两大危害:
一、你已经遇到了,修改时可能出现主键冲突,虽然你只是交换两个键值,交换后正常,但是交换时就冲突了。
二、主键本身是有唯一索引的作用的,每个主键都内置一个索引记录,当主键修改时,索引也会跟着修改,会导致索引的杂乱,影响索引的查找速度,虽然可以事后重整索引,但是重整……
[/Quote]
主键冲突算是最好的情况了吧,如果改主键而且正好没冲突的话,造成业务逻辑混乱就搞大了
qldsrx 2012-02-04
  • 打赏
  • 举报
回复
你错了,不是添加一个无意义的主键,是有意义的主键。
首先你必须明确一点,主键在插入到数据库后就不能随便修改其值,否则有两大危害:
一、你已经遇到了,修改时可能出现主键冲突,虽然你只是交换两个键值,交换后正常,但是交换时就冲突了。
二、主键本身是有唯一索引的作用的,每个主键都内置一个索引记录,当主键修改时,索引也会跟着修改,会导致索引的杂乱,影响索引的查找速度,虽然可以事后重整索引,但是重整过程整个数据库将无法使用。

因此你必须选择插入后不再有改动的列作为主键,如果没有这个列,就必须使用自增长列,该列本身也许意义不大,但是日后通过它来修改或删除记录时,效率就会提高,特别是使用数据库游标时,主键列的检索,通过索引快速定位,速度可以大大提高。
cnwin 2012-02-04
  • 打赏
  • 举报
回复
看来添加一个无意义的主键是比较快的解决方案。当然为了数据库“干净”也可以放弃这种想法。但是如果将来升级时想实现这种效果势必会要牵涉到更改用户端的表结构。难道就没有好方法了吗?
cnwin 2012-02-03
  • 打赏
  • 举报
回复
大家的意见建议都不错。说实话这个行号本身对于应用程序来说关系不是太大,顶多引用该表单的下一表单明细中可以确定原单据明细行。主要不过就是为了实现一种所“输”即所得(显示),也就是用户可以按照自己的意愿将物料按照自己的次序填写到明细中,再查看时,还是显示当时输入的顺序。当然如果不提供插入功能也就无所谓了。智叟以提供插入功能,是因为也许用户会发现漏下没有输入的,而这一项可能与某乡之间有点联系,用户希望在那项之前或之后输入这漏下得项。所以才想了这个行号办法。这不是一个物理行号,而是逻辑行号。此种想法也仅是从细化用户体验方面考虑的。
mcycsnd007 2012-02-03
  • 打赏
  • 举报
回复
增加1个列 存储你的行号 现有行号继续作为主键使用 在主键更新前 记录你的行号到新列中
abel_master 2012-02-03
  • 打赏
  • 举报
回复
update xxx set line=line+1 where line>=要插入的行号
insert xxxxxxxxxxxxxxx

我试了试 能跑通 用sqlCmd吧。。
另外要是能改数据库结构的话最好改掉
主键应该使用无意义的序列
cnwin 2012-02-03
  • 打赏
  • 举报
回复
不是排序的问题,是要实现"用户输入顺序",用户插入行不一定是按代码排序的,他可能有自己的想法.那等他以后察看时如何能还原他当时的输入顺序呢?
fanshu_c 2012-02-03
  • 打赏
  • 举报
回复
弄一个列排序不久得了么……
cnwin 2012-02-03
  • 打赏
  • 举报
回复
试了一下,如果不用行号做主键,添加自增列。发现使用数据邦定的话,第一次插入行保存没问题,第二次插入行保存时会出现并发冲突问题。看来要实现这种效果也不是简单的事了。
DSIOF3KIDSKTR 2012-02-02
  • 打赏
  • 举报
回复
[Quote=引用 11 楼 cnwin 的回复:]

其实这个行号仅是为了让用户用起来像是填Excel表的感觉,而且DataGridView在绑定了数据源后是无法用DataGridview的Insert的。所以加了这个行号,一是作为联合主键之一,二是让用户有这种次序感。本来还想用更改行号的方法让用户有个可“插入行”的感觉。不保存数据没事,仅仅操作一下,由于是逆序更改的行号所以没问题。甚至“有时候”插入点在底端几行保存也没问题。但仔细的实验发现了问题……
[/Quote]

[Quote=引用 9 楼 athwind 的回复:]

你的设计本身就有严重的问题,行号无论如何都不能作为主键,如果你的主从关系只有一级,而且不大可能再添加子bom了,那么子表主键使用自动增长列比较好,而且省事,将主表ID作为子表的外键。
[/Quote]
让用户看起来有Excel的感觉?如果删除行呢,还会有断层的Excel的感觉呢
行号可以动态构造,也可以加一个字段专门存储行号
wedding123 2012-02-02
  • 打赏
  • 举报
回复
重新考虑数据库设计,为什么非要用行号+表单号做主键呢?
新增GUID的主键应该更可行。
WAN 2012-02-02
  • 打赏
  • 举报
回复
因此,这个行号最好是作为非绑定列来处理
WAN 2012-02-02
  • 打赏
  • 举报
回复
如果要保留,只得手工提交入库。可以从后往前逐条更改,逐条提交。

但还是建议行号不要存入数据库,DataGridView绑定了数据源后还可以再额外插入非绑定列的
加载更多回复(11)

110,534

社区成员

发帖
与我相关
我的任务
社区描述
.NET技术 C#
社区管理员
  • C#
  • Web++
  • by_封爱
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

让您成为最强悍的C#开发者

试试用AI创作助手写篇文章吧