Si y’a bien une galère dans la gestion de résultats, c’est bien la … pagination.
L’aspect le plus important étant bien évidemment la performance. Et de ce point de vue, j’avoue que même côté DBA ça cherche toujours à optimiser.
Et pourtant, on se prend vraiment la tête pour pas grand chose des fois :-D. Eh oui vraiment ! Il existe dans ASP.Net MVC un moyen simple qui quand on connaît ce qu’il y a derrière (merci ReSharper ;-)) on comprend mieux pourquoi on dormira moins bête et surtout on se demandera pourquoi on ne l’a pas fait plus tôt.
Je vous le promet, y’a pas de magie, pas de chose prétendue et non tenue et même je vous promet aucun SQL !
PagedList.Mvc
Voici le nom du package NuGet à avoir dans votre besace pour réaliser une pagination simple et rapide.
Voici un exemple de code
[Route("LocalizationLevel1/{page?}")] public ActionResult ListLocalizationLevel1(int? page) { var items = DbContext.LocalizationLevel1.OrderBy(m => m.Id); return View("LocalizationLevel1List", items.ToPagedList(page ?? 1, 50)); }
Je ne détaillerai pas le contexte, il s’agit simplement de vous illustrer un exemple. Nous avons dans ce code, la récupération des éléments à paginer grâce à
var items = DbContext.LocalizationLevel1.OrderBy(m => m.Id);
Vous remarquez que je ne fait pas appel à .ToList() ou autre pour descendre les éléments et donc réaliser la requête. Mais pourquoi ? Tout simplement parce que c’est la suite qui va le faire avec des données de filtres supplémentaires qui vont optimiser de fait la requête.
items.ToPagedList(page ?? 1, 50)
En effet, si vous explorer le code du package soit sur GitHub soit avec ReSharper si vous l’avez ou encore avec dotPeek, vous découvrirez cette ligne dans le constructeur
this.Subset.AddRange(pageNumber == 1 ? (IEnumerable) Enumerable.ToList((IEnumerable) Queryable.Take(Queryable.Skip(superset, 0), pageSize)) : (IEnumerable) Enumerable.ToList((IEnumerable) Queryable.Take(Queryable.Skip(superset, (pageNumber - 1) * pageSize), pageSize)));
Et là on comprend que EntityFramework nous donne tous les outils pour faire le boulot.
Lorsque l’on est pas sur la première page, on « skip » les (n°page-1) * pageSize éléments
(pageNumber - 1) * pageSize
Et on ne prend que les pageSize éléments
(IEnumerable<T>) Queryable.Take<T>(Queryable.Skip<T>(superset, (pageNumber - 1) * pageSize), pageSize)
Et pis c’est tout 😀