【问题标题】:Master-detail using ClientDataSet.AppyUpdates with separate DataSetProvider使用带有单独 DataSetProvider 的 ClientDataSet.AppyUpdates 的主详细信息
【发布时间】:2011-11-23 21:05:12
【问题描述】:

我将两个 ClientDataSet 用于主从关系,并为每个 CDS 使用一个 DataSetProvider。我没有对细节使用嵌套 CDS,因为我对主从关系进行了内存过滤。

我遇到的问题是当我需要将更改应用到底层数据库(火鸟)时。对于细节插入,我必须先应用主,对于细节删除,我必须先应用细节(不违反数据库中的主从关系)。到现在为止还挺好。但是,当我的详细 CDS 包含 INSERT 和 DELETE 时,我该怎么办?然后我不能在主 CDS 之前或之后应用它。

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

【问题讨论】:

  • 以 KTDataComponents 为例
  • 在他的主页 (kterz.blogspot.com) 上,该组件的链接似乎已损坏。您有有效的链接吗?
  • 您应该始终按照用户顺序做事。如果用户确实先更改了 master,那么它应该首先应用 master 的更改。问题是:你将如何检测这个订单?

标签: delphi master-detail tclientdataset


【解决方案1】:

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

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

注意:由于我是凭记忆解释的,所以我可能对某些细节有误,但这个想法很重要。尝试一下,您会找到解决方案的。

【讨论】:

    【解决方案2】:

    我会先申请master,然后再申请detail。

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

    【讨论】:

    • 您知道如何覆盖 ApplyUpdates 以便我可以跳过已删除的记录吗?
    【解决方案3】:

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

    【讨论】:

    • 如果在 DataSetProvider 启动之前显式启动事务。所有组件都使用相同的事务,直到您明确提交或回滚它。这样就可以保证数据库状态的“原子性”。
    猜你喜欢
    • 2016-08-16
    • 1970-01-01
    • 2019-02-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-05-30
    相关资源
    最近更新 更多