【问题标题】:How to refresh modified records to CloneSource before ApplyUpdates?如何在 ApplyUpdates 之前将修改后的记录刷新到 CloneSource?
【发布时间】:2014-11-24 19:21:03
【问题描述】:

所以我有一个带有嵌套详细信息 (cdsD1) 的 ClientDataset (cdsM1)。我需要在 ApplyUpdates 之前打印它,所以我克隆它们(cdsMclone 和 cdsDclone)并过滤主克隆,只显示一个主记录。

打印后,我需要更新记录。起初我尝试过这样的事情:

cdsMclone.Edit;
cdsMclone.FieldByName('DATEPRINTED').AsString := Now;
cdsMclone.Post;
cdsMclone.ApplyUpdates(0);

但是在此之后,如果我在源客户端数据集中更改任何内容,cdsM1.ApplyUpdates(0) 会产生冲突(我的意思是您应该在OnReconcileError 中回复)。但是这个不应该显示给用户。此外,使用这种方法,我至少向数据库发送了两个请求。

一种解决方法是使用CloneSource 属性。示例:

cdsMclone.CloneSource.Edit;
cdsMclone.CloneSource.FieldByName('DATEWASPRINTED').AsString := Now;
cdsMclone.CloneSource.Post;

这样,我就可以毫无顾虑地拨打cdsM1.ApplyUpdates(0)。但我真的不喜欢这个。似乎代码正在改变它不应该直接做的事情。另外,如果将来我需要更改嵌套细节中的某些内容,代码会是什么样子?

还有其他方法可以将克隆的客户端数据集的更改返回到源吗?

【问题讨论】:

    标签: delphi delphi-xe tclientdataset


    【解决方案1】:

    我只有 Rave 5 for D7 的版本,但以下内容对我有用,无需在 Master 表、CloneCursor 或其他类似工具上使用过滤器,即可仅生成当前的 Master-Detail 报告排在法师。因此,它应该可以避免您的问题并避免需要解决方法。

    下面显示的 MasterConnFirst 和 MasterConnValidateRow 事件处理程序是在 Delphi IDE 中为 master 的 TRvDataSetConnection 设置的。

    TForm1 = class(TForm)
    [...]
      cdsMaster: TClientDataSet;
      cdsDetail: TClientDataSet;
    [...]
    public
      { Public declarations }
      Recs : Integer;
      BM : TBookmark;
    end;
    
    procedure TForm1.btnReportClick(Sender: TObject);
    begin
      BM := cdsMaster.GetBookmark;  // place a bookmark on the current Master row
      Recs := 0;  // counter for Master records processed by the report
      RvProject.Execute;
    end;
    
    procedure TForm1.MasterConnFirst(Connection: TRvCustomConnection);
    begin
      // The following moves the cdsMaster to its current row, causing the RvReport to skip the
      // Master rows preceding it.
      cdsMaster.GotoBookmark(BM);
      cdsMaster.FreeBookmark(BM);
    end;
    
    procedure TForm1.MasterConnValidateRow(Connection: TRvCustomConnection; var
        ValidRow: Boolean);
    begin
      //  This counts the number of Master records processed and returns ValidRow := False
      //  if the Master current row has already been processed.  This will cause
      //  Master rows after our current one to be skipped by the RvReport.
    
      Inc(Recs);
      if Recs > 1 then
        ValidRow := False;
    end;
    

    无论如何,如果这对你有用,那么这个答案的其余大部分可能都可以删除,我稍后会这样做。

    注意事项:

    • TRvDataSetConnection 也有一个带有 EOF 参数的 OnEOF 事件,根据 Rave5 开发人员指南,一旦处理了当前主行,您应该能够将其设置为 True,以生成 RVReport认为 master 没有更多您感兴趣的行。但是在 Rave 5.0.4(D7 附带的版本)中,即使为此事件分配处理程序也会导致报告不生成任何内容。可能是 Rave 5.0.4 中的一个错误,并且可能已在更高版本中修复。遗憾的是 OnEOF 处理程序似乎不起作用,因为使用 ValidateRow 处理程序似乎效率有点低,考虑到报告引擎仍然必须迭代当前记录之后的主记录。

    • TRvDataSetConnection 有两个属性,DataIndex 和 DataRows,应该通过将 DataIndex 设置为当前记录的 RecNo 和DataRows 为 1。DataIndex 工作正常,但 DataRows 设置似乎被忽略了,可能是 5.0.4 中的另一个错误,但可能在以后的版本中可以正常工作。

    【讨论】:

    • 我不知道如何只打印 Rave Reports 中的当前记录而不过滤数据集。
    • 我建议的解决方法运行良好。所以我认为不需要使用文件创建副本。但我真的不知道是否可以只打印当前记录而不过滤数据集并且还没有找到帮助。
    • 是的,您的回答有帮助。为此 +1。
    【解决方案2】:

    如果您的克隆是使用 CloneCursor() 创建的,则原始数据集和克隆共享相同的基础数据集。它们不是单独的数据集,只是相同数据的两个不同视图。

    您没有提供用于将原始数据集限制为 1 条记录的过滤器的详细信息。但是,我怀疑您对记录的更改与该过滤器的条件相冲突,从而导致您看到的冲突错误。

    使用克隆可以避免这种情况,因为克隆的数据集没有应用此过滤器。它是一个带有自己过滤器的单独视图。因此没有冲突。

    以这种方式通过克隆游标修改底层数据集没有问题。如前所述,克隆和克隆源在同一个数据集上运行,因此这似乎完全符合您的要求。

    您的应用程序的一个方面将受益于一些文档,但是对于那些在未来数月和数年内维护该代码的人来说,使代码中涉及的意图和依赖关系更加明显。

    【讨论】:

    • 感谢您的回答。我正在使用CloneCursor(),您所描述的正是我所期待的。但不是我要实现的……嗯,过滤器是基于 PrimaryKey 的。所以,至少在理论上,不应该与任何数据或条件相冲突。类似于cdsMclone.filter := 'IDMaster = '+ cdsM1.fieldByName('IDMASTER').asString;。随着打印顺利,我认为代码也可以。也许我需要创建一个示例代码来展示这一点。不幸的是,我只能在明天再次访问代码时才能做到这一点。
    猜你喜欢
    • 1970-01-01
    • 2018-11-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多