Googling tìm thấy rất nhiều bài báo nói rằng hoàn toàn không thể có với ClientDataSets lồng nhau mà không đóng và mở lại CDS chính mà OP không muốn làm trong trường hợp này. Tuy nhiên ...
Câu trả lời ngắn cho q là có, trong trường hợp đơn giản hợp lý mà tôi đã thử nghiệm, và nó khá đơn giản, nếu một chút dài gió; nhận được các bước cần thiết phải mất một lúc để tìm ra.
Mã bên dưới và bao gồm các nhận xét giải thích cách hoạt động và một số vấn đề tiềm ẩn và cách tránh hoặc hoạt động xung quanh chúng. Tôi đã chỉ thử nghiệm nó với TAdoQueries cho nhà cung cấp CDS.
Khi tôi bắt đầu xem xét tất cả điều này, nhanh chóng trở nên rõ ràng rằng với bậc thầy thông thường + thiết lập chi tiết, mặc dù nhà cung cấp + CDS vui lòng làm mới dữ liệu chủ từ máy chủ, chúng đơn giản sẽ không làm mới chi tiết hồ sơ khi chúng đã được đọc từ máy chủ lần đầu tiên kể từ khi cdsMaster được mở. Điều này có thể là do thiết kế của khóa học.
Tôi không nghĩ mình cần đăng DFM để đi kèm với mã. Tôi đơn giản có AdoQueries được thiết lập theo cách chi tiết thông thường (với truy vấn chi tiết có PK của master như một tham số), một DataSetProvider chỉ vào AdoQuery chủ, một CDS chủ chỉ vào nhà cung cấp, và một chi tiết cDS chỉ vào DataSetField của cdsMaster. Để thử nghiệm và xem những gì đang diễn ra, có các DBGrids và DBNavigators cho mỗi bộ dữ liệu này. Tóm lại, cách mã bên dưới hoạt động là tạm thời lọc chủ AdoQuery và quá trình tổng hợp CDS thành hàng hiện tại và sau đó buộc làm mới dữ liệu của chúng và dữ liệu dtail cho hàng chính hiện tại. Làm theo cách này, không giống như bất kỳ khác tôi đã cố gắng, kết quả trong các hàng chi tiết lồng nhau trong lĩnh vực DataSet của cdsMaster nhận được làm mới.
Btw, các ngõ hẻm mù khác mà tôi đã thử bao gồm và không có poFetchDetailsOnDemand được đặt thành true, ditto cdsMaster.FetchDetailsOnDemand. Rõ ràng "FetchDetailsOnDemand" không có nghĩa là ReFetchDetailsOnDemand!
tôi chạy vào một hai vấn đề hoặc nhận tôi "giải pháp" làm việc, stickiest một được mô tả trong câu hỏi này SO: (!) Refreshing a ClientDataSet nested in a DataSetField
tôi đã xác minh rằng điều này hoạt động chính xác với Sql Server 2000 back-end, bao gồm việc chọn lên các thay đổi dữ liệu hàng được kích hoạt tại máy chủ từ ISqlW. Tôi cũng đã xác minh, bằng cách sử dụng Profiler của Sql Server, lưu lượng mạng trong quá trình làm mới chỉ liên quan đến hàng chính duy nhất và các chi tiết của nó.
Delphi 7 + Win7 64 bit, btw.
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;
AFAIK, trong bộ dữ liệu khách hàng lồng nhau, bạn không thể sử dụng 'Làm mới' cho tập dữ liệu chi tiết. Kiểm tra [bài viết] này (http://edn.embarcadero.com/article/29825) được viết bởi Cary Jensen và tìm kiếm từ làm mới. –
Trong bài viết được liên kết, người xác nhận đã nói rằng tôi không thể làm mới tập dữ liệu mà không có nhà cung cấp tập dữ liệu. được. Vì vậy, là cách duy nhất để làm mới toàn bộ tập dữ liệu tổng thể? – EProgrammerNotFound
Không chắc chắn 100% nhưng có vẻ như vậy. Dù sao, bạn có vấn đề gì với việc làm mới tập dữ liệu tổng thể? –