2013-10-14 23 views
9

Có cách nào để làm mới chỉ Chi tiết dữ liệu mà không cần tải lại tất cả tập dữ liệu chính không?Làm mới Tập dữ liệu lồng nhau với poFetchDetailsOnDemand

đây là những gì tôi đã cố gắng cho đến nay:

DM.ClientDataSet2.Refresh;  
DM.ClientDataSet2.RefreshRecord; 

Tôi cũng đã cố gắng:

DM.ClientDataSet1.Refresh; 

Nhưng phương pháp trên làm mới toàn bộ tập dữ liệu tổng thể, không chỉ là kỷ lục hiện nay.

Bây giờ, các mã sau đây dường như làm bất cứ điều gì:

DM.ClientDataSet1.RefreshRecord; 

Có một cách giải quyết hoặc một cách thích hợp để làm những gì tôi muốn? (Có thể một interposer ...)

bổ sung Thông tin:

ClientDataSet1 = Master Dataset

ClientDataSet2 = chi tiết DataSet, như sau: *

object ClientDataSet2: TClientDataSet 
    Aggregates = <> 
    DataSetField = ClientDataSet1ADOQuery2 
    FetchOnDemand = False 
    ..... 
end 

tính Provider :

object DataSetProvider1: TDataSetProvider 
    DataSet = ADOQuery1 
    Options = [poFetchDetailsOnDemand] 
    UpdateMode = upWhereKeyOnly 
    Left = 24 
    Top = 104 
    end 
+0

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. –

+0

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

+0

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ể? –

Trả lời

2

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; 
+0

Rất vui, tôi sẽ kiểm tra và sớm quay lại với nhiều nhận xét về điều này. – EProgrammerNotFound

Các vấn đề liên quan