使用带有单独 DataSetProvider 的 ClientDataSet.AppyUpdates 主从

发布于 2024-12-17 20:19:35 字数 303 浏览 4 评论 0原文

我使用两个 ClientDataSet 来与每个 CDS 的 DataSetProvider 建立主从关系。我不使用嵌套 CDS 来处理详细信息,因为我对主从关系进行了内存中过滤。

我遇到的问题是当我需要将更改应用到底层数据库(firebird)时。对于详细信息插入,我必须首先应用主信息,对于详细信息删除,我必须首先应用详细信息(不违反数据库中的主从关系)。到目前为止,一切都很好。但是,当我的详细 CDS 混合有 INSERT 和 DELETE 时,我该怎么办?那么我就无法在主 CDS 之前或之后应用它。

在不使用嵌套 CDS 的情况下如何处理这种情况?

I use two ClientDataSets for a master-detail relationship with a DataSetProvider for each CDS. I don’t use a nested CDS for the detail, since I do an in-memory filtering for the master-detail relationship.

The problem I have is when I need to apply my changes to the underlying database (firebird). For detail INSERTs I have to apply the master first and for detail DELETEs I have to apply the detail first (without violating the master-detail relationship in the db). So far so good. But what shall I do when my detail CDS has a mixture of INSERTs and DELETEs? Then I cannot apply it before or after the master CDS.

How can I handle such situation, without using nested CDS?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

瑶笙 2024-12-24 20:19:35

通常,您插入/更新一条主记录,然后处理详细信息(插入、更新、删除)。解决问题的一种方法是将整个操作放在事务中(在进行任何更改之前启动事务),插入/更新主记录(单个记录),执行MasterCDS.ApplyUpdates,处理详细记录,执行 DetailCDS.ApplyUpdates,最后提交或回滚整个事务。由于您的 CDS 处于主/详细关系,一旦 Post 发布,DetailCDS 将“查看”MasterCDS 中的记录,并且您将在 MasterCDSApplyUpdates 后立即获取主键值。这样您就可以保持引用完整性(外键约束),并且可以在 DetailCDS 上执行任何操作。

此外,TClientDataSetTDataSetProvider 上都有一些事件,可以让您(几乎)完全控制整个过程,因此请仔细查看所有可用事件。

注意:当我根据记忆解释这一点时,我可能对一些细节有误,但这个想法很重要。尝试一下,您就会找到解决方案。

Usually, you insert/update one master record and then you work with details (insert, update, delete). One way to solve your problem is to place the entire operation in a transaction (start transaction before making any changes), insert/update master record (single record), do MasterCDS.ApplyUpdates, work with detail records, do DetailCDS.ApplyUpdates and finally commit or rollback the entire transaction. Since your CDS are in a master/detail relationship, DetailCDS will "see" records in MasterCDS as soon as they are Posted and you will get primary key value as soon as you ApplyUpdates on MasterCDS. That way you maintain referential integrity (foreign key constraints) and you can do whatever you have on the DetailCDS.

Additionally, there are events on both TClientDataSet and TDataSetProvider that give you (almost) complete control over the entire process, so take a closer look at all available events.

NOTE: I may be wrong about some details as I'm explaining this from my memory, but the idea is important. Experiment a bit and you'll find the solution.

那些过往 2024-12-24 20:19:35

我会先应用主线,然后再应用细节。

如果您删除主记录,我将通过覆盖 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

Then”的方法,在 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;

I would apply the master and then the detail.

In the case where you delete a master record I would cascade delete the detail records by overriding the BeforeApplyUpdates event.

When you delete the detail you will again need to override the BeforeApplyUpdates. If the master record is missing do not bother to perform a delete.

You can 'skip' the deletion of detail records by using a custom update command. The only reason to do this is to stop datasnap from generating a SQL command itself and then failing because rows affected = 0. I would probably use something like

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

Then in the BeforeUpdateRecord event you call this command

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;
只有影子陪我不离不弃 2024-12-24 20:19:35

当使用单独的数据集提供程序时,我发现每个 DSP 中的更新都在单独的事务中(至少对于 Interbase 而言)。我并不关心这一点,但您的应用程序可能要求所有数据集保持一致。

When using separate Data Set Providers, I found that the updates in each DSP were in a separate transaction (at least with Interbase). I was not concerned with this, but your application might require all datasets to be kept consistent.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文