【问题标题】:How to apply updates of Delphi TClientDataset in specified order?如何按指定顺序应用 Delphi TClientDataset 的更新?
【发布时间】:2013-03-14 07:36:04
【问题描述】:

我需要按指定顺序应用更新 (ClientDataSet.ApplyUpdates): - 删除为第一 - 修改为第二个 - 作为第三个插入

它们按照完成的顺序应用。

【问题讨论】:

  • AFAIK 无法处理这个问题,我不知道这是什么原因
  • 我使用缓存更新。您可能在数据库中有一些约束(例如,记录或唯一索引的有效性重叠),如果用户插入记录,而不是编辑或删除另一条记录,则最终结果集可能是正确的,但不能应用。例如:我有一个唯一的 KEY=1,VAL=A 的数据库记录。我插入一条 KEY=1 且值 VAL=B 的记录,并删除 KEY=1、VAL=A 的记录。这按默认顺序失败,但按 DELETE、MODIFY、INSERT 顺序成功。
  • 是的,这将失败,因为您以错误的顺序执行此操作,这会导致错误的数据(有 2 行具有相同的主键) - 可能只是一秒钟,但错误是错误的,不不管多久
  • 是的,我知道。但是数据是由用户修改的——这就是为什么我需要重新排序操作来删除、修改、插入来解决它。
  • 我很确定所有数据操作都由您的应用程序控制。因此,由您决定抛出异常或简单更新记录而不是追加/删除

标签: delphi tclientdataset


【解决方案1】:

请参阅 KTDataComponents 了解如何实现这一点

此外,我有时会通过在提供者端的 OnUpdateData 事件处理程序中切换到特定索引来形成所需的更新顺序。为了不破坏增量处理,必须使用一些技巧,但这是完全可行的

procedure TLogResolver.LogUpdateRecord(Tree: TUpdateTree);
var
  I: Integer;
  CurVal: Variant;
  fld: TField;
  SaveRecNo: Integer;
  OldIndexName: WideString;
  OldIndexFieldNames: WideString;
begin
  if(TClientDataSet(Tree.Delta).IndexName<>'')or(TClientDataSet(Tree.Delta).IndexFieldNames<>'') then begin
    OldIndexName:=TClientDataSet(Tree.Delta).IndexName;
    OldIndexFieldNames:=TClientDataSet(Tree.Delta).IndexFieldNames;
    SaveRecNo:=Tree.Delta.RecNo;
    Tree.Delta.Edit;                       // vavan
    for I := 0 to Tree.Delta.FieldCount - 1 do begin
      fld:=Tree.Delta.Fields[I];
      { Blobs, Bytes and VarBytes are not included in result packet }
      if {(fld.IsBlob) or} (fld.DataType in [ftBytes, ftVarBytes]) then // vavan allowed blobs
        continue;
      CurVal := fld.NewValue;
      if not VarIsClear(CurVal) then begin
        fld.Value:=CurVal;  { TODO -ovavan -cSIC! : edit delta }
      end;
    end;
    Tree.Delta.Post; // vavan
    TClientDataSet(Tree.Delta).IndexName:=''; { TODO -ovavan -cSIC! : reset delta index to get correct original recno in order not to break reconcilation mechanism }
  end;
  try
    Tree.ErrorDS.IndexFieldNames:='ERROR_RECORDNO';
//    Tree.InitErrorPacket(nil, rrApply);
    TreeInitErrorPacket(Tree,nil, rrApply);
    for I := 0 to TVPacketDataSet(Tree.Delta).NewValueFields.Count - 1 do
    begin
      fld:=TVPacketDataSet(Tree.Delta).NewValueFields[i];
      { Blobs, Bytes and VarBytes are not included in result packet }
      if {(Tree.Delta.Fields[I].IsBlob) or} // vavan allowed blobs
         (fld.DataType in [ftBytes, ftVarBytes]) then
        continue;
      CurVal := fld.NewValue;
      if not VarIsClear(CurVal) then begin { TODO 2 -ovavan -ccheck! : get rid of this check since we only process modified fields? }
        Tree.ErrorDS.Fields[6+fld.Index].Value := CurVal; { TODO -ovavan -ccheck : ErrorDS fieldd structure is identical to delta but with extra 6 leading fields }
      end;
    end;
    Tree.ErrorDS.Post;
  finally
    if(OldIndexName<>'')then begin
      TClientDataSet(Tree.Delta).IndexName:=OldIndexName;
      Tree.Delta.RecNo:=SaveRecNo;
    end else
    if(OldIndexFieldNames<>'')then begin
      TClientDataSet(Tree.Delta).IndexFieldNames:=OldIndexFieldNames;
      Tree.Delta.RecNo:=SaveRecNo;
    end;
  end;
end;

【讨论】:

  • 你能说得更具体些吗?如果我在 OnUpdateData 中更改索引,那么它的顺序正确,但行为错误 - 我认为这是因为 delta 数据集包含多行编辑(原始行是第一行,然后是第二行中更改的字段。) .如果我更改订单,我会一团糟。
  • 根据您的要求,您可以创建仅用于更新订购的额外字段。然后在 OnUpdateData(或 CDS 端)中,您可以根据需要的顺序填写它,在更新的情况下保持旧/新记录“配对”
  • 如果我保留“配对”记录的顺序,它第一次可以正常工作。但是,如果第一次 applyupdates 失败并且用户在下一次 applyupdates 上再次修改了数据,它就会出错 - 数据出现问题可能是由于更改了数据集行顺序。我找不到问题所在 :(
  • 正确,每当新值被修改以传播回 CDS 或在应用更新期间发生错误时,需要临时重置增量索引,以免破坏协调逻辑。我个人在我自己的自定义解析器中的 LogUpdateRecord/LogUpdateError 中这样做
  • 有什么好方法可以将增量索引重置为原始顺序吗?如果我只是清除索引属性,它没有帮助。所以现在我使用两个字段,一个用于原始订单,第二个用于我的订单。但它并不那么优雅。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-03-01
  • 2018-04-30
  • 1970-01-01
  • 2016-12-15
  • 2021-08-18
  • 1970-01-01
  • 2014-11-03
相关资源
最近更新 更多