3

データベース内の複数のTClientDataSetからのデータを保存する複雑なトランザクションがあります。

これらのClientDataSetの1つは、常にデータを下にあるテーブルに追加します。既存のレコードがどこから来たかに関係なく、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

sthを望むでしょう。このように機能します(少なくとも計算フィールドがない場合)。

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、レコード属性をリセットします。これは、ハッキーなアプローチをかなり役に立たないものにします。

たぶん、データベース対応コントロールをバインドして、データソースのDataLinkのBufferCountを設定することが役立つかどうかを確認することができます。または、子孫のClientDataSetでGetRecordをオーバーライドしてみてください。しかし、私はそれが努力する価値があるとは思えません。

[編集]

record属性は、「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を含むform / datamouleの前にあります)

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は「デルタ」のみを考慮し、デルタがない可能性があります。これを実現するにはさまざまな方法があります。以下の例では、DataSetにプロバイダーがあり、それにイベントハンドラーを配置できることを前提としています。

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 に答える