2017-10-09 82 views
6

Korzystanie z Delphi Seattle. Mam aplikację, która wykonuje różne wywołania REST. Niektóre z tych wywołań mogą zwrócić 10-20 wierszy za pośrednictwem JSON, podczas gdy inne mogą zwrócić 30-40 tysięcy wierszy. Ustawiłem serwer REST, aby zwracał wiersze w partiach po 1000. Kiedy dane wracają do mojego klienta, używam narzędzia RestDataAdapater, DataSource i zestawu danych klienta, aby ujawnić dane tak, jakby były tabelą lokalną. Ta część wydaje się działać dobrze. Jeśli znajdujemy się na końcu 1000 wierszy, zmieniam adres URL i żądam następnej partii 1000 wierszy.Delphi - Jak utworzyć ogólne wywołanie REST

Moje wyzwanie: Chciałabym to streścić, aby jedna procedura mogła obsłużyć wszystkie scenariusze (przynajmniej w przypadku wywołań GET). Częścią trudną jest jak obsłużyć zestaw danych 1000-wierszowych danych źródłowych/danych klienta? Przykład może pomóc w wyjaśnieniu ... Chciałbym móc wykonać coś takiego ...

... 
genericREST_Get(baseURL, resource, suffix); // This would actually execute the REST call, where the components are in Datamodule DM1. 
while not dm1.ds_Generic.DataSet.Eof do 
     begin 
     ... some kind of processing 
     dm1.ds_Generic.DataSet.Next; 
     end; 

Jak mogę obsłużyć przekraczanie progu rzędu 1000 wierszy? Gdy mój program wywołujący (pokazany powyżej) przechodzi z wiersza 1000 do 1001, interfejs API REST musi zażądać następnego zestawu 1000 wierszy od serwera. Chociaż wiem, JAK to zrobić, nie wiem, GDZIE to zrobić. Chcę, aby "uzyskać następne 1000 wierszy" w ogólnej procedurze (znanej jako standardowa procedura REST_Get). Nie chcę, aby każda z procedur wywoływania miała z tym problem.

Załóżmy, że wszystkie procedury będą TYLKO poruszać się do przodu, nigdy do tyłu.

Odpowiedz

2

Oto kilka opcji do rozważenia:

1) Po prostu wszystkie dane
30-40 tys rzędach nie jest dużo, aby trzymać w pamięci dla większości zastosowań. Nawet jeśli musisz wykonywać wiele połączeń, aby uzyskać dane, które możesz zrobić z góry. Jeśli zawsze będzie pętli nad wszystkimi danymi czas będzie takie samo, jeśli się go z góry lub wewnątrz pętli:

repeat 
    PartialData := genericREST_Get(baseURL, resource, suffix); 
    // CopyDataSet is actually a FireDac method that I don't see on ClientDataSet 
    // Basically just .Append and copy all fields with matching names. 
    FullDataMemTable.CopyDataSet(PartialData); 
    until PartialData.IsEmpty; 

2) Jeśli chcesz mieć tylko jedną grupę danych naraz pamięć można zawinąć DataSet w innym obiekcie, który powiela niektóre z połączeń (Eof, FieldByName, Next, itp.) Kiedy "Next" trafi eof, próbujesz uzyskać więcej danych. Przykładem tutaj jest samodzielna klasa, ale możesz również wprowadzić te publiczne metody do swojego modułu DataModule. Następnie zamiast czegoś takiego jak dm1.ds_Generic.DataSet. Dalej po prostu wywołujemy dm1.Next.

constructor TDataFetcher.Create(BaseUrl, Resource, Suffix: string); 
begin 
    FBaseUrl := BaseUrl; 
    FResource := Resource; 
    FSuffix := Suffix; 
end; 

procedure TDataFetcher.Open; 
begin 
    FData := genericREST_Get(FBaseURL, FResource, FSuffix); 
end; 

procedure TDataFetcher.GetNextData; 
begin 
    FData := genericREST_Get(FBaseURL, FResource, FSuffix); 
end; 

function TDataFetcher.Eof: boolean; 
begin 
    result := FData.Eof; 
end; 

function TDataFetcher.FieldByName(FieldName: string): TField; 
begin 
    result := FData.FieldByName(FieldName); 
end; 

procedure TDataFetcher.Next; 
begin 
    FData.Next; 
    if FData.Eof then 
    begin 
    GetNextData; 
    end; 
end; 

Inne opcje:
a) Dziedziczenie z TClientDataSet Można również osiągnąć poprzez wyprowadzenie nowej klasy z TClientDataSet i nadrzędnym MoveBy:

function MoveBy(Distance: Integer): Integer; virtual; 

Jeśli dziedziczone MoveBy ustawia EOF następnie możesz załadować następny zestaw danych. Jeśli jednak spróbujesz tego, upewnij się, że rozważasz wszystkie przypadki użycia. Na przykład, co chcesz zrobić, jeśli osoba dzwoniąca używa .Last? To jest jedna z zalet, jaką ma klasa otoki. Dzwoniący nie może zrobić niczego poza tym, co wyjawiasz.

function TMyDataSet.MoveBy(Distance: Integer): Integer; override; 
begin 
    inherited MoveBy 
    if self.Eof then 
    begin 
    FetchMoreData; 
    end; 
end; 

b) FetchOnDemand
ClientDataSet ma wbudowane wsparcie dla FetchOnDemand. Nie wiem jak to wpłynęłoby na działanie RestDataAdapter. Jestem pewien, że biorąc pod uwagę wystarczającą ilość pracy, mógłbyś uzyskać dostawcę, który zwróciłby całkowitą liczbę rekordów, a następnie pozwoliłby ClientDataSet zażądać większej ilości rekordów w razie potrzeby.