我使用两个ClientDataSets与每个CDS的DataSetProvider建立主 - 细节关系。我没有使用嵌套的CDS来处理细节,因为我对主 - 细节关系进行了内存过滤。
我遇到的问题是当我需要将更改应用于底层数据库(firebird)时。对于细节INSERT,我必须先应用master,对于细节DELETE,我必须首先应用细节(不违反db中的master-detail关系)。到现在为止还挺好。但是当我的细节CDS混合使用INSERT和DELETE时,我该怎么办?然后我不能在主CDS之前或之后应用它。
如何在不使用嵌套CDS的情况下处理这种情况?
答案 0 :(得分:2)
通常,您插入/更新一个主记录,然后使用详细信息(插入,更新,删除)。解决问题的一种方法是将整个操作放在事务中(在进行任何更改之前启动事务),插入/更新主记录(单个记录),执行MasterCDS.ApplyUpdates
,使用详细记录,执行DetailCDS.ApplyUpdates
,最后提交或回滚整个事务。由于您的CDS处于主/详细关系,DetailCDS
只要MasterCDS
Post
就会“看到”ApplyUpdates
中的记录,您将在MasterCDS
时获得主键值DetailCDS
在TClientDataSet
上{1}}。这样就可以保持参照完整性(外键约束),你可以对TDataSetProvider
做任何事情。
此外,{{1}}和{{1}}上的事件可让您(几乎)完全控制整个过程,因此请仔细查看所有可用事件。
注意:我可能错了一些细节,因为我是从记忆中解释这个,但这个想法很重要。尝试一下,你会找到解决方案。
答案 1 :(得分:0)
我会应用主人,然后是细节。
如果您删除主记录,我会通过覆盖 BeforeApplyUpdates 事件级联删除详细信息记录。
删除详细信息后,您将再次需要覆盖BeforeApplyUpdates。如果缺少主记录,则无需执行删除操作。
你可以跳过'使用自定义更新命令删除详细记录。执行此操作的唯一原因是停止datasnap自身生成SQL命令然后失败,因为受影响的行= 0.我可能会使用类似
的内容IF EXISTS (SELECT * FROM dbo.ParentTable WHERE ParentKey = @ParentKey)
BEGIN
DECLARE @rowcount INT
DELETE
FROM dbo.ChildTable
WHERE ChildKey = @ChildKey
SET @rowcount = @@ROWCOUNT
IF @rowcount <> 1
BEGIN
RAISERROR('Record not found.(%d)', 15, 1, @rowcount) WITH SETERROR
END
END
然后在BeforeUpdateRecord事件中调用此命令
case UpdateStatus of
ukDelete:
begin
sqlDeleteChild.Parameters.ParamByName('@ChildKey').Value := DeltaDS.FieldByName('ChildKey').OldValue;
sqlDeleteChild.Parameters.ParamByName('@ParentKey').Value := DeltaDS.FieldByName('ParentKey').OldValue;
sqlDeleteChild.Execute;
end;
...
end;
Applied := true;
答案 2 :(得分:0)
当使用单独的数据集提供程序时,我发现每个DSP中的更新都在一个单独的事务中(至少使用Interbase)。我并不关心这一点,但您的应用程序可能要求所有数据集保持一致。