3

我有一个复杂的事务,它将来自多个 TClientDataSets 的数据保存在数据库中。

其中一个 ClientDataSet 总是将数据附加到底层表,例如。生成 INSERT 语句,无论现有记录来自何处。

我现在强制插入:

// Create temp table, assign all target data, 
// Empty target table, append data from temp

Tmp := TClientDataSet.Create; 
Tmp.Data := Table.Data; 

Table.MergeChangeLog; 
Table.EmptyDataSet;

Tmp.First; 
// Append all records 
While not Tmp.Eof do
begin
  Table.Append;  
  for i := 0 to Table.FieldCount - 1 do
    Table.Fields[i].Value := Tmp.Fields[i].Value 
  Table.Post; 

  Tmp.Next;
end;

Tmp.Free;

有没有更简单的方法可以将所有记录标记为已插入?

4

1 回答 1

1

一个人会希望……。这样会起作用(至少在没有计算字段的情况下);

uses
  dsintf;

[..]
procedure TForm1.Button1Click(Sender: TObject);
begin
  ClientDataSet1.First;
  while not ClientDataSet1.Eof do begin
    PRecInfo(ClientDataSet1.ActiveBuffer +
        ClientDataSet1.RecordSize).Attribute := dsRecNew;
    ClientDataSet1.Next;
  end;
end;

好吧,它可以工作,但只要没有重新检索数据。即TCustomClientDataSet.GetRecord重新设置记录属性。我猜这使得 hacky 方法毫无用处。

也许可以尝试绑定一个数据感知控件,看看设置 DataSource 的 DataLink 的 BufferCount 是否会有所帮助。或者,尝试在后代 ClientDataSet 中覆盖 GetRecord。但我怀疑这是否值得努力。

[编辑]

记录属性可以在“AfterScroll”事件中被破解。例如,这将有助于测试 UpdateStatus 以返回“usInserted”的代码。

procedure TForm1.ClientDataSet1AfterScroll(DataSet: TDataSet);
begin
  PRecInfo(DataSet.ActiveBuffer + DataSet.RecordSize).Attribute := dsRecNew;
end;

测试是否插入了所有记录

procedure TForm1.Button1Click(Sender: TObject);
begin
  ClientDataSet1.First;
  while not ClientDataSet1.Eof do begin
    if not (ClientDataSet1.UpdateStatus = usInserted) then
      raise Exception.Create('The record is not inserted');
    ClientDataSet1.Next;
  end;
end;



可以派生一个新的 TClientDataSet 来检索始终“插入”的记录。

(类型声明在包含 ClientDataSet 的表单/数据模块之前)

type
  TClientDataset = class(dbclient.TClientDataSet)
    function GetRecord(Buffer: PChar; GetMode: TGetMode; DoCheck: Boolean):
        TGetResult; override;
  end;
[..]
implementation

function TClientDataset.GetRecord(Buffer: PChar; GetMode: TGetMode;
  DoCheck: Boolean): TGetResult;
begin
  Result := inherited GetRecord(Buffer, GetMode, DoCheck);
  if Result = grOk then
    PRecInfo(Buffer + RecordSize).Attribute := dsRecNew;
end;

现在对于所有记录,UpdateStatus 将返回“usInserted”。

编辑

我终于明白,目的是为所有记录生成插入 SQL。我们不会通过修改 DataSet 的记录属性来实现这一点,ApplyUpdates 只考虑“Delta”,我们可能没有 Delta。可能有不同的方法来实现这一点,下面的示例假设 DataSet 有一个 Provider 并且我们能够在其上放置一个事件处理程序。

type
  TForm1 = class(TForm)
    [..]
  private
    procedure DeltaAfterScroll(DataSet: TDataSet);
    [..]

implementation

procedure TForm1.DeltaAfterScroll(DataSet: TDataSet);
begin
// The UpdateTree of the Resolver of the Provider will visit each 
// record to get the UpdateStatus
  PRecInfo(DataSet.ActiveBuffer + DataSet.RecordSize).Attribute := dsRecNew;
end;


type
  TAccessCCDS = class(TCustomClientDataSet);

procedure TForm1.Button1Click(Sender: TObject);
var
  Count: Integer;
begin
  ClientDataSet1.MergeChangeLog;
// Since there's no "Delta", ApplyUpdates will return immediately.
// Hence, we'll force an update by calling DoApplyUpdates, bypassing the
// ChangeCount test, and update with the "Data".
// Reconcilation is left out for simplicity.
  TAccessCCDS(ClientDataSet1).DoApplyUpdates(ClientDataSet1.Data, 0, Count);
end;

procedure TForm1.DataSetProvider1UpdateData(Sender: TObject;
  DataSet: TCustomClientDataSet);
begin
// Will be called once when ApplyUpdates is called.
  TAccessCCDS(DataSet).AfterScroll := DeltaAfterScroll;
end;
于 2010-02-08T03:38:51.100 回答