出现一个怪问题,请帮帮忙,本人很急(200分)

  • 主题发起人 主题发起人 fstao
  • 开始时间 开始时间
F

fstao

Unregistered / Unconfirmed
GUEST, unregistred user!
数据库是sql server 7,有一个表是dbo.hbku,其脚本为:
CREATE TABLE [dbo].[hbku] ([id] [int] NOT NULL ,[no] [varchar] (10) NULL ,
[mc] [varchar] (20) NULL ,[hl] [float] NULL ,[bz] [varchar] (100)
NULL ,[sign] [varchar] (10) NULL) ON [PRIMARY]
ALTER TABLE [dbo].[hbku] WITH NOCHECK ADD
CONSTRAINT [PK_hbku] PRIMARY KEY NONCLUSTERED
(
[id]
) ON [PRIMARY] ,
CONSTRAINT [IX_hbku] UNIQUE NONCLUSTERED
(
[no]
) ON [PRIMARY] ,
CONSTRAINT [IX_hbku_1] UNIQUE NONCLUSTERED
(
[mc]
) ON [PRIMARY]

我在中间服务器定义一个接口:
function TAppServer3.ApplyMasterData(Delta: OleVariant;
MaxError: Integer;
var ErrorCode: Integer): OleVariant;
begin
Result:=ProviderMaster.ApplyUpdates(Delta,MaxError,ErrorCode);
//ProviderMaster(TDataSetProvider),用Ado访问数据库。Master(Tadodataset)连接
// dbo.hbku
//ProviderMaster.dataset:=master;
end;

在前端添加TDCOMConnection、cdsmaster(Tclientdataset)和DBgrid,
cdmaster.Providername=providermaster,
在cdmaster的事件AfterPost:
procedure TForm1.cdsmasterAfterPost(DataSet: TDataSet);
var
IMida :IAppServer3;
iRecord:Integer;
begin
DCOMco.GetServer.QueryInterface(IAppServer3,IMida);
IMida.ApplyMasterData(cdsMaster.Delta,0,iRecord);
end;

注册中间服务器,然后运行客户端,DBgrid显示如下:
id no mc hl bz sign
添加第一条数据时
id no mc hl bz sign
1 a b
然后方向键向下移(相当触发AfterPost事件),保存数据,没有
问题。添加第二条数据时:
id no mc hl bz sign
1 a b
2 b c
当方向键向下移时,出现错误:
Project PClient.exe raised exception class EOleException with message
'Viloation of PRIMARY KEY constraint 'PK_hbku'.Cannot insert duplicate
key in object 'hbku''.Process stopped.Use Step or Run to continue.
它说违反primary key,但是我输入数据并没有任何重复现象,但为什么这个错误呢?
但是如果我这样做:
cdsmaster.close;
cdsmaster.open;
然后再一次添加第二条数据:
id no mc hl bz sign
1 a b
2 b c
保存它没有问题,但是在没有:cdsmaster.close和cdsmaster.open之前,再添加
第三条数据时:
id no mc hl bz sign
1 a b
2 b c
3 c d
保存的时候又出现同样的错误,为什么?
是不是我写的中间接口是不是有问题呢?我这样做目的是前端添加数据,然后中
间提交的功能。请各位看看我在中间这样写事件行不行,有没有其他的方法?
当然如果把cdsmaster的AfterPost事件改为:cdsmaster.applyupdates(0),就没
任何问题.
中间是Madias服务器。
 
>>当然如果把cdsmaster的AfterPost事件改为:cdsmaster.applyupdates(0),就没任何问题.
既然如此,为什么要用你上面那种写法呢?
 
因为cdmaster.applyupdates(0)是属于Late Binding的方法,而我上面写的方法 是属于
Early Binding的方法。听说Early Binding比Late Binding效率要高。
 
我一般认为:
1.效率高如果没有高到某种程度,一般是不值得尝试新方法的。
2.你上面这段就这里用了一下early binding(如果是的话),
其他的地方没什么改进,能有多少效率上的优势呢?
至于这个具体问题,以后有时间在研究一下...
现在我的猜想为:你第二次传cdsmaster.delta的时候,
这个delta包含第一条插入的记录,而你的server端的apllyupdates
并不能正确判断(具体是谁的原因不知道),从而再次插入
第一条记录,当然导致主码重复。如果想解决,我想应该是阅读
Tclientdataset.applyupdates的代码,从而找到方法...
 
你的问题出在:
客户端Delta给appserver,apply保存后,客户端的delta未将已经提交
的记录清除,第2次applyupdates,传送delta给appserver的时候,第一
次送去的delta的改变记录的内容也一起发去了(就是说,第一次送delta
包含增加记录,第2次送delta又送出去了,所以主键冲突)。
做法:
appserver中的provider的 ApplyUpdates 返回的 OleVariant 值
返回给客户端,客户端把它用 clientdataset.Reconcile 来清除
delta中已经正确提交的记录。
另外,我认为,你的这种做法和直接 clientdataset.ApplyUpdates
好象没有什么差别
 
fstao:如果你还要继续讨论请定期提前你的帖子,如果不想继续讨论请结束帖子。
 
to fasto:
Pipi 说的对啊,DBClient.pas 中 TClientDataSet 的 ApplyUpdate 定义如下:

function TClientDataSet.ApplyUpdates(MaxErrors: Integer): Integer;
begin
CheckBrowseMode;
if ChangeCount = 0 then
Result := 0 else
Reconcile(DoApplyUpdates(Delta, MaxErrors, Result));
end;
再继续深究do
ApplyUpdates 发现最后也是 RemoteDataModule 调用相应DataSetProvider
的ApplyUpdates方法,比你的方法多了对Reconcile的调用。
另,ClientDataSet 的 ApplyUpdates 应该是 early binding 的,至少
 
多人接受答案了。
 
后退
顶部