Как добиться самостоятельного клонирования TADODataSet?
Сценарии таковы:
У нас есть некоторые таблицы SQL. Мы выполняем SQL-запрос к этой таблице, и у нас есть результаты в объекте TADOQuery.
var
qryOryginal, qryClone: TADOQuery;
begin
//setup all the things here
qryOryginal.Active := True;
qryClone.Clone(qryOryginal, ltBatchOptimistic);
qryOryginal.Delete; //delete in qryOryginal casues that qryClone deletes its record too!
end;
Итак, после клонирования DataSet мой qryClone должен хранить и независимые данные (по крайней мере, я так думал). Однако выполнение Delete для qryOryginal вызывает ту же операцию для qryClone. Я не хочу этого
Есть идеи?
Я знаю, что могу хранить данные в другом месте, возможно, в TClientDataSet, но сначала я хотел бы попробовать вышеуказанное решение.
Спасибо заранее за ваше время.
3 ответа
Клонирование просто клонирует курсор на наборе данных, не дублируя данные, хранящиеся в наборе данных.
Если вам нужно иметь два независимых данных, вам необходимо скопировать данные из исходного набора данных во второй.
Если вы хотите прочитать или изменить один набор данных без изменения текущего курсора на наборе данных, то вы можете использовать метод Clone.
Вы можете использовать набор записей TADODataSet для клонирования TADODataSet.
ds1.Recordset := CloneRecordset(ds2.Recordset);
Эта версия работает от Delphi XE. ADOInt обновлен определениями библиотеки типов для MDAC 2.8
uses ADOInt, Variants;
function CloneRecordset(const Data: _Recordset): _Recordset;
implementation
function CloneRecordset(const Data: _Recordset): _Recordset;
var
newRec: _Recordset;
stm: Stream;
begin
newRec := CoRecordset.Create as _Recordset;
stm := CoStream.Create;
Data.Save(stm, adPersistADTG);
newRec.Open(stm, EmptyParam, CursorTypeEnum(adOpenUnspecified),
LockTypeEnum(adLockUnspecified), 0);
Result := newRec;
end;
Эта версия должна использоваться для версий Delphi до Delphi XE. ADOR_TLB генерируется из msado28.tlb.
uses ADOInt, ADOR_TLB, Variants;
function CloneRecordset(const Data: ADOInt._Recordset): ADOInt._Recordset;
implementation
function CloneRecordset(const Data: ADOInt._Recordset): ADOInt._Recordset;
var
newRec: ADOR_TLB._Recordset;
stm: Stream;
begin
newRec := ADOR_TLB.CoRecordset.Create as ADOR_TLB._Recordset;
stm := CoStream.Create;
(Data as ADOR_TLB._Recordset).Save(stm, adPersistADTG);
newRec.Open(stm, EmptyParam, CursorTypeEnum(adOpenUnspecified),
LockTypeEnum(adLockUnspecified), 0);
Result := newRec as ADOInt._Recordset;
end;
Мне больше нравится реализация с TClientDataSet, потому что мы можем свободно редактировать его по мере необходимости после копирования.
var
MyADOStoredProc: TADOStoredProc;
DataSetProvider: TDataSetProvider;
ClientDataSet: TClientDataSet;
DataSource: TDataSource;
...
// here now we have an opened ADOStoredProc object MyADOStoredProc
// let's copy data from it
DataSetProvider := TDataSetProvider.Create(Self);
DataSetProvider.Name := 'DataSetProvider' + FormatDateTime('_yyyy_mm_dd_hh_nn_ss', Now);
DataSetProvider.DataSet := MyADOStoredProc;
ClientDataSet := TClientDataSet.Create(Self);
ClientDataSet.ProviderName := DataSetProvider.Name;
DataSource := TDataSource.Create(Self);
DataSource.DataSet := ClientDataSet;
ClientDataSet.Open;
MyADOStoredProc.Close;
ClientDataSet.First;
// here we can modify our ClientDataSet as we need, besides MyADOStoredProc is closed
if not ClientDataSet.Eof then
ClientDataSet.Delete;
...
Или второй способ, используйте Devexpress dxMemData
. Очень полезный и простой в использовании компонент.
var
MD: TdxMemData;
SP: TADOStoredProc;
...
...
// and after opening stored procedure:
MD.Close;
MD.Open;
MD.LoadFromDataset(SP);