FireDAC BatchMove 从 MemoryTable

FireDAC BatchMove from MemoryTable

我的传入数据加载到 TFDMemTable 中(reader)。作者是一个TFDQuery。

传入数据如果不在目标中则应插入,否则更新。匹配基于 UUID 字段。

我无法正确定义 UUID 字段是键。

这是一个代码示例 - 不起作用。 FBatchMove.Execute 失败,因为找不到任何关键字段。

procedure TSubDB.FindDestRecord(ASender: TObject; var AFound: Boolean);
var
  aSrc: TBytes;
begin
  SetLength(aSrc, 16);
  aSrc := FReader.DataSet.FieldByName('UUID').AsBytes;
  AFound := FWriter.DataSet.Locate('UUID', aSrc, []);
end;

function TSubDB.LoadDB(const aFilename: string): boolean;
var
  FQry: TFDQuery;
  FBatchMove: TFDBatchMove;
  FReader: TFDBatchMoveDataSetReader;
  FWriter: TFDBatchMoveDataSetWriter;
  FMemTable: TFDMemTable;
begin
  FQry := TFDQuery.Create(nil);
  FQry.Connection := dmFB.myDB;
  FQry.FetchOptions.AssignedValues := [evItems];
  FQry.FetchOptions.Items := [fiBlobs, fiDetails];
  FBatchMove := TFDBatchMove.Create(nil);
  FBatchMove.Analyze := [taDelimSep, taHeader, taFields];
  FReader := TFDBatchMoveDataSetReader.Create(FBatchMove);
  FWriter := TFDBatchMoveDataSetWriter.Create(FBatchMove);
  FMemTable := TFDMemTable.Create(nil);
  try
    FMemTable.LoadFromFile(aFileName, sfBinary);
    //Not sure how to make the BatchMove recognize that UUID is the key for OnFindDestRecord
    FMemTable.IndexFieldNames := 'UUID';
    with FMemTable.Indexes.Add do
    begin
      Name :='idxUUID';
      Fields := 'UUID';
      Active := true;
    end;
    FMemTable.IndexName := 'idxUUID';
    FMemTable.IndexesActive := true;
    FMemTable.FieldByName('UUID').ProviderFlags := FMemTable.FieldByName('UUID').ProviderFlags + [pfInKey];
    FReader.DataSet := FMemTable;
    FQry.SQL.Text := 'select * from test';
    FWriter.DataSet := FQry;
    FBatchMove.OnFindDestRecord := FindDestRecord;
    FBatchMove.Mode := dmAppendUpdate;
    //None of the above seems to keep the pfInKey in the UUID field's ProviderFlags
    FBatchMove.Execute;
    FQry.Open;
    FQry.Close;
  finally
    FMemTable.Free;
    FWriter.Free;
    FReader.Free;
    FBatchMove.Free;
    FQry.Free;
  end;
end;

我真的很感激批量移动的工作示例(目标有数据,所以批量移动模式是 dmAppendUpdate)。

这里的关键是编写器需要是一个设置了 TableName 的 TFDBatchMoveSQLWriter。这样目标就定义了主键,然后用它来决定是插入还是更新。

function TSubDB.LoadDB(const aFilename: string): boolean;
var
  FQry: TFDQuery;
  FBatchMove: TFDBatchMove;
  FReader: TFDBatchMoveDataSetReader;
  FWriter: TFDBatchMoveSQLWriter;
  FMemTable: TFDMemTable;
begin
  FQry := TFDQuery.Create(nil);
  FQry.Connection := dmFB.myDB;
  FQry.FetchOptions.AssignedValues := [evItems];
  FQry.FetchOptions.Items := [fiBlobs, fiDetails];
  FBatchMove := TFDBatchMove.Create(nil);
  FBatchMove.Analyze := [taDelimSep, taHeader, taFields];
  FReader := TFDBatchMoveDataSetReader.Create(FBatchMove);
  FWriter := TFDBatchMoveSQLWriter.Create(FBatchMove);
  FMemTable := TFDMemTable.Create(nil);
  try
    FMemTable.LoadFromFile(aFileName, sfBinary);
    FReader.DataSet := FMemTable;
    FQry.SQL.Text := 'select * from test';
    FWriter.Connection := dmFB.myDB;
    FWriter.TableName := 'test';
    FBatchMove.Mode := dmAppendUpdate;
    FBatchMove.Execute;
    FQry.Open;
    FQry.Close;
  finally
    FMemTable.Free;
    FWriter.Free;
    FReader.Free;
    FBatchMove.Free;
    FQry.Free;
  end;
end;