Поиск в Google находит множество статей, в которых говорится, что это вообще невозможно с вложенными ClientDataSets без закрытия и повторного открытия главной CDS, чего OP не хочет делать в этом случае. Однако ...
Короткий ответ на вопрос: да, в довольно простом случае, который я тестировал, и он довольно прост, хотя и немного многословен; Чтобы понять, как правильно сделать необходимые шаги, потребовалось некоторое время.
Код приведен ниже и включает комментарии, объясняющие, как он работает, и несколько потенциальных проблем, а также то, как их можно избежать или обойти. Я протестировал его только с TAdoQueries, питающим поставщика CDS.
Когда я начал разбираться во всем этом, вскоре стало очевидно, что при обычной настройке master+detail, хотя Providers+CDS с удовольствием обновляют мастер-данные с сервера, они просто не будут обновлять detail записи после того, как они были прочитаны с сервера в первый раз с момента открытия cdsMaster. Это может быть по дизайну, конечно.
Я не думаю, что мне нужно публиковать DFM, чтобы идти с кодом. Я просто настроил AdoQueries обычным способом master-detail (с подробным запросом, имеющим PK мастера в качестве параметра), DataSetProvider указывал на главный AdoQuery, главный CDS указывал на провайдера, а подробный cDS указывал на DataSetField файла cdsMaster. Чтобы поэкспериментировать и посмотреть, что происходит, для каждого из этих наборов данных есть DBGrids и DBNavigator.
Вкратце, приведенный ниже код работает так, чтобы временно отфильтровать мастер AdoQuery и мастер CDS до текущей строки, а затем принудительно обновить их данные и данные dtail для текущей основной строки. Выполнение этого способа, в отличие от любого другого, который я пробовал, приводит к обновлению строк сведений, вложенных в поле DataSet cdsMaster.
Кстати, другие тупики, которые я пробовал, включали и не включали poFetchDetailsOnDemand в значение true, то же самое cdsMaster.FetchDetailsOnDemand. Очевидно, что «FetchDetailsOnDemand» не означает ReFetchDetailsOnDemand!
Я столкнулся с одной или двумя проблемами, когда мое «решение» заработало, самая липкая из них описана в этом вопросе SO: -a-datasetfield/24722787#24722787">Обновление ClientDataSet, вложенного в DataSetField
Я проверил, что это правильно работает с серверной частью Sql Server 2000 (!) , включая получение изменений данных строки, запущенных на сервере из ISqlW. Я также проверил, используя Sql Server Profiler, что сетевой трафик при обновлении включает только одну главную строку и ее детали.
Delphi 7 + Win7 64-бит, кстати.
procedure TForm1.cdsMasterRowRefresh(MasterPK : Integer);
begin
// The following operations will cause the cursor on the cdsMaster to scroll
// so we need to check and set a flag to avoid re-entrancy
if DoingRefresh then Exit;
DoingRefresh := True;
try
// Filter the cdsMaster down to the single row which is to be refreshed.
cdsMaster.Filter := MasterPKName + ' = ' + IntToStr(MasterPK);
cdsMaster.Filtered := True;
cdsMaster.Refresh;
Inc(cdsMasterRefreshes); // just a counter to assist debugging
// release the filter
cdsMaster.Filtered := False;
// clearing the filter may cause the cdsMaster cursor to move, so ...
cdsMaster.Locate(MasterPKName, MasterPK, []);
finally
DoingRefresh := False;
end;
end;
procedure TForm1.qMasterRowRefresh(MasterPK : Integer);
begin
try
// First, filter the AdoQuery master down to the cdsMaster current row
qMaster.Filter := MasterPKName + ' = ' + IntToStr(MasterPK);
qMaster.Filtered := True;
// At this point Ado is happy to refresh only the current master row from the server
qMaster.Refresh;
// NOTE:
// The reason for the following operations on the qDetail AdoQuery is that I noticed
// during testing situations where this dataset would not be up-to-date at this point
// in the refreshing operations, so we update it manually. The reason I do it manually
// is that simply calling qDetail's Refresh provoked the Ado "Insufficient key column
// information for updating or refreshing" despite its query not involving a join
// and the underlying table having a PK
qDetail.Parameters.ParamByName(MasterPKName).Value := MasterPK;
qDetail.Close;
qDetail.Open;
// With the master and detail rows now re-read from the server, we can update
// the cdsMaster
cdsMasterRowRefresh(MasterPK);
finally
// Now, we can clear the filter
qMaster.Filtered := False;
qMaster.Locate(MasterPKName, MasterPK, []);
// Obviously, if qMaster were filtered in the first place, we'd need to reinstate that later on
end;
end;
procedure TForm1.RefreshcdsMasterAndDetails;
var
MasterPK : Integer;
begin
if cdsMaster.ChangeCount > 0 then
raise Exception.Create(Format('cdsMaster has %d change(s) pending.', [cdsMaster.ChangeCount]));
MasterPK := cdsMaster.FieldByName(MasterPKName).AsInteger;
cdsDetail.DisableControls;
cdsMaster.DisableControls;
qDetail.DisableControls;
qMaster.DisableControls;
try
try
qMasterRowRefresh(MasterPK);
except
// Add exception handling here according to taste
// I haven't encountered any during debugging/testing so:
raise;
end;
finally
qMaster.EnableControls;
qDetail.EnableControls;
cdsMaster.EnableControls;
cdsDetail.EnableControls;
end;
end;
procedure TForm1.cdsMasterAfterScroll(DataSet: TDataSet);
begin
RefreshcdsMasterAndDetails;
end;
procedure TForm1.cdsMasterAfterPost(DataSet: TDataSet);
// NOTE: The reason that this, in addition to cdsMasterAfterScroll, calls RefreshcdsMasterAndDetails is
// because RefreshcdsMasterAndDetails only refreshes the master + detail AdoQueries for the current
// cdsMaster row. Therefore in the case where the current cdsMaster row or its detail(s)
// have been updated, this row needs the refresh treatment before we leave it.
begin
cdsMaster.ApplyUpdates(-1);
RefreshcdsMasterAndDetails;
end;
procedure TForm1.btnRefreshClick(Sender: TObject);
begin
RefreshcdsMasterAndDetails;
end;
procedure TForm1.cdsDetailAfterPost(DataSet: TDataSet);
begin
cdsMaster.ApplyUpdates(-1);
end;
person
MartynA
schedule
13.07.2014
Refresh
для подробного набора данных. Прочтите эту статью, написанную Кэри Дженсен, и найдите слово обновления. - person Guillem Vicens   schedule 15.10.2013closed dataset
довольно странная. Я нашел эту ссылку, где говорится, что вы должны иметь возможность использоватьRefreshRecord
в набореnested
clientDataset. Я предполагаю, что что-то неправильно настроено. Пожалуйста, проверьте предыдущую ссылку, а также эту. - person Guillem Vicens   schedule 19.10.2013Closed Dataset
, но все равно не работает - person EProgrammerNotFound   schedule 24.10.2013