如何处理自增主键的表?(100分)

  • 主题发起人 主题发起人 ljqin
  • 开始时间 开始时间
L

ljqin

Unregistered / Unconfirmed
GUEST, unregistred user!
在SQL Server中定义了一个主键自增的表,就是其主键(Primary key)
比如说字段名为NID,是自增的。即每添加一个记录,该字段自动加1,这样
就不用让用户去输入与他无关的主键。
使用Delphi 3 的TTable和TDBNavigator操作这样的表时,因为不希望
用户直接操作主键,所以NID在屏幕上不出现。当Insert以后,输入各字段值
然后post时,出现“NID Required”错误。用TTable的Fields Editor将
NID字段的属性设置成ReadOnly和非Required的。则上述错误不再出现,却
出现Record/Key Deleted错误。
虽然可以用设置Exception的办法过滤这个错误,但程序运行总是不正常
 
这是一种正常的现象,这是因为Delphi使用表的关键字
来定位记录,由于你采用了自增字段,而在记录提交到
SQL Server前,该字段值是NULL, SQL Server在记录该
数据时,修改了这个字段,这就使得Delphi在提交后
重新根据内存缓冲区中的数据定位记录时,不能找到这
一条记录,故产生Record/Key Deleted.
根本解决方法是自己维护这个自增字段的值,另外建一个
表,保存该字段下一个应该取的值,这样在Before Post
事件中给该自增字段赋值,并将附加表中的值加一。
 
屏幕上不出现关键字段,请用TTable的Fields Editor将该字段的Visible
设置为False, 不要去动ReadOnly和Required.
 
非常感谢Delphi的帮助,在桌面数据库中我也确实是这样做的,但对于后台的
例如SQL Server甚至是多用户的Access我都不太愿意这样做。对于集中数据库
这样做会带来完整性上的问题,而且操作上会增加不少麻烦。yysun的办法让
是我需要的那种类型,但我试了,似乎不起作用。
不管如何都非常感谢两位,我身边用Delphi的人很少,很高兴能和大家讨论。
 
我想delphi的话是对的,不过既然是SQL server 可不可以考虑用
存储过程来完成键值的维护?
 
对于自增字段,原则上应该用Query来做.

Insert Into SomeTable
Values( 'Field2 Value','Field3 Value');

把这个自增字段设成是不需要输入的(Sql Server默认),向上面那样,
不用写这个字段.

不要用TTabel,它对于SQL数据库而言又慢又不规范.

 
我没有用过SQL server 不过在InterBase 中解决这种问题
是用发生器, 我想数据库服务器 sql 和interBase在功能上
有强弱 但性质应该一样, SQL应该有类似的东西
 
DELPHI 2对自增的SQL服务器有缺陷(3我没有试过),实际上应该是BDE的缺陷,
当使用触发器时一定要小心,查阅DELPHI 2程序设计大全,有详细的论述,(那本绿的
120几元的),顺便说,那本书的确不错!
 
不会呀,早在几年前我用D2写过一个连ms Sql Server的,
几乎每个表都是自增字段,一点问题都没有.
那时候BDE还是2.x或者3吧.

BTW,如果程序已经写得差不多了,而且都是用Table的,
Table.BeforePost里生成SQL把字段加入,然后Cancel;
再执行这个SQL.
只是错误处理要重写了.
 
由于自增字段的问题越来越多,我也试了一下,
结果用TQuery+RequestLive没发现任何问题。

不知各位所说的错误是什么情况?
顺便说一句,强烈建议永远不要用TTable!
^^^^^^^^^^^^^^^^^
 
给TTable加上UpdateSQL试试。
 
我个人做这个问题时用三种办法
1。正如JZY所说,您可以用把TABLE加上UPDATESQL 来做

2。 使用存储过程来做(最好不要用触发器,就是生成器)
使用存储过程的好处是
因为一般涉及到主键 的自增域大多和主副表有关
使用存储过程可以同时完成这个任务
declare @id int
insert dbo.tbl1 (id,......) values(id........)
select @id=max(id) from dbo.tbl1
update dbo.tbl2 set .........
/* 这样完成多表更新 */

3. 不使用自增字段,而是,使用另外一个表来做本来需要自增字段的表的记数器
这样做的好处是对于大数据表,效率会有很大提高

实现方法是: 定义一个 dbo.idcount 里面只有一条记录,存放主表记录计数

declare @idcount int

update dbo.idcount set field1=xxx where field1=一个不存在的值
/* 这样做是强制更新SQL SERVER的 锁定级别 为更新锁 */
/* 因为下面的SELECT 动作是共享锁定级别,可能会引起DEAD LOCK */
select @idcount=field1 from dbo.idcount

insert into dbo.table1 (id........) values(@idcount..........)
/* 插入主表 */
insert or update 副表............

如果你采用DBGRID来做记录的编辑的话,对于大型数据库访问,一定不要用
TTABLE,因为TTABLE性能效率都要比TQUERY差很多
应该使用UPDATESQL + Tquery 来完成,这是铁的经验
另外您还可以在DBGRID POST动作之前截获其动作,不用它来做更新,
再用你自己的过程去更新数据库,然后重新刷新表就可以了
这样做其实和UPDATESQL 的动作过程类似,只是这样你可以自己实现UPDATE过程了
如果需要例子,EMALI我 hehe@tonghua.com.cn
 
接受答案了.
 
后退
顶部