2016-01-31 12 views
6

Ich frage mich, ob es eine Möglichkeit gibt, Seitenumbruch in C# gegen DocumentDB mit oder ohne ihren Linq-Provider zu implementieren?Seitenumbruch in C# gegen DocumentDB ohne Überspringen

Szenario: Ich habe eine API, die Paginierung unterstützt, sendet der Benutzer in der Seite, die sie mit einem pagesize auf zusammen aussehen wollen, wie zum Beispiel:

public virtual async Task<HttpResponseMessage> Get(int? page = DefaultPage, int? pageSize = DefaultPageSize)

ich dann diese Parameter verwenden, die Paginieren Daten in der Datenzugriffsschicht mit dem folgenden Code:

return query.Skip((pageNumber - 1) * pageSize).Take(pageSize);

„Was ist das Problem dann ist“, könnte man fragen. Nun, dieser Ansatz und Code funktioniert perfekt mit EF und SQL. Das Problem ist, dass ich DocumentDB verwenden möchte, aber ihre Linq-Implementierung hat keine Unterstützung für Skip. Die einzigen Beispiele, die ich gesehen habe, schließen die Verwendung des Schlüsselwortes TOP oder continuation tokens ein, das nicht passt gut mit mir, Benutzern erlaubend, eine pageNumber und pageSize einzuschicken.

Gibt es eine Implementierung, die es meinen Benutzern noch ermöglicht, pageNumber und pageSize in der Anforderung anzugeben?

Antwort

11

SKIP ist ein Leistungsproblem für SQL und es ist noch schlimmer für NoSQL aufgrund ihrer Skalierung Design. Wir haben die SKIP-Funktionalität von MongoDB verwendet und festgestellt, dass die Abfrage von Grund auf neu erstellt wurde und alle übersprungenen Zeilen weggeworfen wurden. Je später wir in der Liste waren, desto länger dauerte die Abfrage. Trotz der SKIP-Funktionalität mussten wir daher eine performantere Lösung implementieren.

Die Produktmanager bei DocumentDB verstehen das und sind resistent gegen Hinzufügen von SKIP. Wenn sie es tun würden, glaube ich, dass sie es getan hätten, wenn sie TOP hinzugefügt hätten.

Für DocumentDB ist der effizienteste Ansatz, das Fortsetzungstoken zu verwenden und alle Ergebnisse in der Reihenfolge zu speichern, in der sich der Benutzer (und sogar vorhersehbar) befindet. Kontinuierliche Token überleben lange, sodass Sie nicht sofort alle Seiten abrufen müssen.

+1

Hallo Larry, Vielen Dank für Ihre Antwort, die wie klingt ein vernünftiges Argument zu machen. Obwohl ich nicht sehen kann, wie die Verwendung von Fortsetzungstokens und das Zwischenspeichern der Ergebnisse möglich ist, können meine Benutzer beliebige Kombinationen aus "Seite" und "Seitengröße" einsenden. Ja, der höchste Wert der Seite entspricht der Anzahl der Elemente in der Sammlung, obwohl es nicht "unmöglich" wäre, dies zusammen mit all den verschiedenen Kombinationen, die von den Kombinationen 'page' und' pageSize' geliefert werden, zu speichern. Beachten Sie, dass "pageSize" alles von 1 bis etwa 50 sein kann. –

+2

Nehmen wir an, der Benutzer hat die Seitengröße auf 10 gesetzt und Sie haben 27 Zeilen im Cache. Daher hat der Cache nur genügend Zeilen für Seite 1, Seite 2 und einen Teil von Seite 3 im Speicher, wenn der Benutzer Seite 7 anfordert. Ihr Code würde berechnen, dass er mindestens 80 Zeilen im Cache haben muss, um Seite 7 und anzuzeigen Es wird so viele Zeilen mit dem Fortsetzungstoken aus der letzten Anfrage holen. Wenn der Benutzer dann auf Seite 5 zurückspringt, haben Sie diese bereits im Cache und müssen nicht auf DocumentDB zugreifen. In der Praxis können Sie 100 oder sogar 1000 Zeilen im zweistelligen Millisekunden erhalten. –

+0

Vielen Dank für die Erklärung. Das klingt nach einer guten Strategie, zumal es so dynamisch ist, dass meine Benutzer die "pageSize" zwischen verschiedenen Anfragen ändern können. Ich denke, dass Sie den aufgebauten Cache auch in Anfragen für einzelne Ressourcen verwenden könnten, was nett ist. –

5

Während dies Ihre Frage nicht speziell beantwortet, unterstützt Document DB für zukünftige Googler das Paging über Fortführungstoken. Ich habe es ausführlich geschrieben here. Der Code, den Sie brauchen es dieses:

var endpoint = "document db url"; 
var primaryKey = "document db key"; 
var client = new DocumentClient(new Uri(endpoint), primaryKey); 
var collection = UriFactory.CreateDocumentCollectionUri("database id", "collection id"); 

var options = new FeedOptions 
{ 
    MaxItemCount = 100 // <- Page size 
}; 

var query = client.CreateDocumentQuery<Document>(collection, options).AsDocumentQuery(); 

while (query.HasMoreResults) 
{ 
    var result = await query.ExecuteNextAsync<Document>(); 

    // Process paged results 
} 
4

Ich weiß, die Frage bereits eine akzeptierte (und gut gesagt) Antwort wurde aber da diese besondere SO Seite der Top-Ergebnis auf Google nach ist „DocumentDB überspringen“ Ich dachte, ich würde teilen meine Lösung hier, die wirklich nur eine Implementierung dessen ist, was Larry bereits vorgeschlagen hat. Ich habe Fortsetzungstoken und Zwischenspeicherung in Angular verwendet, um einen anständigen Paging-Mechanismus für DocumentDB-Abfragen zu erstellen. Der Schlüssel ist, dass ich auch Sortierung und Filterung erlaube, was die Notwendigkeit des Benutzers reduziert, zu zufälligen Seiten oder sogar zur letzten Seite von Ergebnissen zu springen. Hier ist meine Lösung:

http://www.zoeller.us/blog/2017/7/27/paging-results-with-documentdb

+0

Große Lösung. Ich würde es sehr gerne sehen, dass es aktualisiert wird, um zu unterstützen, alle Seiten (Zufallssprung) in der Navigation anstatt nur der folgenden Seite zu zeigen. – defines