我有一个复杂的事务,可以保存数据库中多个TClientDataSets的数据。
其中一个ClientDataSets总是将数据附加到底层表,例如。生成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;
是否有更简单的方法将所有记录标记为已插入?
答案 0 :(得分: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;
(类型声明之前包含ClientDataSet的表单/ 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只考虑“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;