TUTORIELS 

Pagination des enregistrements à partir d'ASP
(Par J.D. Meier - Fourni par MSDN France)

Un moyen simple pour parcourir les résultats d'une requête en n'affichant qu'un sous-ensemble de résultats par page.  (22 mai 2002)
 

Introduction
L'affichage d'un jeu important d'enregistrements dans une application Active Server Pages (ASP) représente un problème auquel vous avez souvent dû être confronté. Le présent article analyse ce problème et propose une solution et un exemple de code pouvant être facilement modifié pour s'adapter à votre situation particulière. L'exemple de code est conçu pour représenter une solution côté serveur, indépendante du navigateur. J'aborderai au cours de l'article des points qu'il est impératif de considérer pour concevoir votre solution.

Problème
Votre requête a généré un jeu important d'enregistrements. Vous devez trouver un moyen simple pour parcourir les résultats en n'affichant qu'un sous-ensemble de résultats par page. Pour pouvoir réaliser cette procédure efficacement, il est impératif de bien comprendre comment collaborent ActiveX® Data Objects (ADO) et votre base de données.

Solution
Comment partitionner votre jeu d'enregistrements en "pages" plutôt que d'avoir un grand résultat unique ? Une page se compose d'un nombre d'enregistrements spécifiés pour s'afficher conjointement. Si votre jeu d'enregistrements se compose par exemple de 100 enregistrements, vous pouvez visualiser 10 enregistrements par page.

ADO fournit deux méthodes, PageSize et AbsolutePage, qui vous permettent de spécifier le nombre d'enregistrements souhaités par page et de placer le curseur au début d'une page.

Une fois votre jeu d'enregistrements ouvert, les principales étapes sont alors les suivantes :

- Spécifiez un valeur PageSize pour le jeu d'enregistrements. Elle correspond au nombre d'enregistrements à afficher par page.
- Spécifiez le paramètre AbsolutePage pour le jeu d'enregistrements. Cela permet de déplacer le pointeur d'enregistrement au début d'une page donnée dans une séquence de pages.
- Affichez la page d'enregistrements. Pour ce faire, itérez votre jeu d'enregistrements un nombre de fois correspondant au paramètre PageSize ou jusqu'à la fin du fichier.

Exemple de code
L'exemple de code suivant illustre la pagination. Vous pouvez l'utiliser pour créer un prototype destiné à votre propre solution. Dans votre code, assurez-vous que vous respectez bien les points suivants :

- Ajoutez une gestion des erreurs.
- Limitez le nombre d'enregistrements renvoyés par votre requête.
- Filtrez les enregistrements par des critères (créez par exemple une clause WHERE).
- Utilisez une procédure stockée ou une vue.

Assurez-vous de bien modifier mon exemple de code pour pointer vers votre base de données en modifiant la chaîne de connection et l'instruction SQL. Le code utilisant des constantes ADO, telles que adUserServer, vérifiez que vous faites référence à ADO TypeLibrary dans votre fichier Global.asa, ou incluez le fichier ADOVBS.INC dans votre page ASP. Remarque : Visual InterDev® génère automatiquement la référence TypeLibrary lorsque vous définissez une référence du projet sur Microsoft ADO.

Notez que l'exemple fournit deux méthodes permettant de créer une barre de navigation :

- ShowNavBar. Cette méthode permet aux utilisateurs de passer à des pages spécifiques grâce au compteur d'enregistrements. Elle utilise alors les propriétés RecordCount et PageCount.
- ShowNavBarFast. Cette méthode ne permet pas de passer à des pages spécifiques et ne fournit pas de compteur d'enregistrement, mais vous permet de contrôler le nombre d'enregistrements extraits par la propriété CacheSize.


PageThroughRs.Asp

<%@ Language=VBScript %>
<% Option Explicit %>
<SCRIPT LANGUAGE=VBScript RUNAT=SERVER>
   'Assurez-vous de faire référence à ADO Typelib ou utilisez ADOVBS.Inc
   Dim iPageNum, iRowsPerPage

   Main
      Sub Main()
   Dim rst
   Dim sSQL, sConnString

      If Request.QueryString("iPageNum") = "" Then
         iPageNum = 1
      Else
         iPageNum = Request.QueryString("iPageNum")
         iPageNum = CInt(iPageNum)
      End If

      iRowsPerPage = 10

      sConnString = "Provider=SQLOLEDB.1;password=Xyz123;user id=WebUser;" & _
 "Initial Catalog=NorthWind;Data Source=MySQLServer;" & _
 "network=dbmssocn;"

  'L'instruction SQL suivante extrait toutes les colonnes d'une vue SQL.
  'Pour optimiser la performance :
  '- utilisez une procédure stockée, une vue, ou spécifiez des colonnes dans SELECT
  '- utilisez des critères limitant les enregistrements renvoyés 
  '(clause WHERE par exemple)
      sSQL = "SELECT CategoryName, ProductName, QuantityPerUnit,"
      sSQL = sSQL & "UnitsInStock, Discontinued"
 sSQL = sSQL & " FROM [Products By Category]"

      Set rst = GetRecords(sConnString, sSQL)

      WriteTableHeader rst
      WriteTableBody rst, iRowsPerPage, iPageNum
      ShowNavBar rst

      'La méthode ShowFastNavBar n'utilise pas RecordCount
      'ou PageCount, elle extrait uniquement le nombre d'enregistrements
      ' dicté par le paramètre CacheSize du jeu d'enregistrements

      'ShowFastNavBar rst

      CleanUp rst
   End Sub

   Function GetRecords(sConnString, sSQL)
   Dim cnn
   Dim rst

      set cnn = Server.CreateObject("ADODB.connection")
      cnn.connectionString = sConnString
      cnn.Open

      Set rst = Server.CreateObject("ADODB.RECORDSET")

      Set rst.Activeconnection = cnn

      'CursorLocation de adUseClient extrait
      'tous les enregistrements lorsque le jeu d'enregistrements est ouvert.
      'adUseServer permet d'optimiser le paramètre CacheSize
      rst.CursorLocation = adUseServer

      'CacheSize limite les lignes extraites en utilisant un
      'curseur côté serveur. La manipulation porte uniquement
      'sur le nombre d'enregistrements affichés - iRowsPerPage
      rst.CacheSize = iRowsPerPage

      rst.Open sSQL,,adOpenStatic, adLockReadOnly   

      Set GetRecords = rst
   end Function

   Sub WriteTableHeader(rst)
   Dim fld

      Response.Write "<TABLE WIDTH=80% BORDER=1>"
      Response.Write "<TR>"

      'Crée des titres de colonne pour le tableau
      For Each fld in rst.Fields
         Response.Write "<TD><B>" & fld.Name & "</B></TD>"
      Next
      Response.Write "</TR>"
   End Sub

   Sub WriteTableBody(rst, iRowsPerPage, iPageNum)
   Dim iLoop
   Dim fld

      iLoop = 1

      rst.PageSize = iRowsPerPage
      rst.AbsolutePage = iPageNum

      'Écrit la page d'enregistrements active
      Do While (Not rst.EOF) and (iLoop <= iRowsPerPage)
         Response.Write "<TR>"
            For Each fld in rst.Fields
               Response.Write "<TD>" & fld.value & "</TD>"
            Next
         iLoop = iLoop + 1
         rst.MoveNext
         Response.Write "</TR>"
      Loop
      Response.Write "</TABLE>"
   End Sub

   Sub ShowNavBar(rst)
   Dim iPageCount
   Dim iLoop
   Dim sScriptName

      'Cette version permet une navigation utilisateur plus riche mais
      'repose sur RecordCount et PageCount, qui inversent
      'les avantages de la spécification d'un paramètre CacheSize pour un
      'curseur coté serveur.

      Response.Write "<BR><BR>"
      sScriptName = Request.ServerVariables("SCRIPT_NAME")

      If iPageNum > 1 Then
         Response.Write " <a class="n" href=" & sScriptName & "?iPageNum="
         Response.Write (iPageNum -1) & "><< Previous</a>"
      End If

      iPageCount = rst.PageCount
      Do Until iLoop > iPageCount
         If iLoop = iPageNum Then
            Response.Write " <B>" & CStr(iLoop) & "</B>"
         Else
            Response.Write " <a class="n" href=" & sScriptName & "?iPageNum=" & _
            Cstr(iLoop) & ">" & iLoop & "</a>"
         End If
         iLoop = iLoop + 1
      Loop

      If Not rst.EOF Then
         Response.Write " <a class="n" href=" & sScriptName & "?iPageNum="
         Response.Write (iPageNum +1) & "> Next >></a><BR>"
      Else
         Response.Write "<BR>"
      End If

      Response.Write "Page " & iPageNum & " of " & iPageCount & "<BR>"
      Response.Write rst.RecordCount & " Records"    
   End Sub

   Sub ShowFastNavBar(rst)
   Dim iPageCount
   Dim iLoop
   Dim sScriptName

  'Cette méthode est très efficace en spécifiant un paramètre CacheSize
  'et en utilisant un curseur côté serveur, car elle n'utilise ni
  'RecordCount ni PageCount. Cela se fait au détriment 
  'de l'expérience de l'utilisateur.

      Response.Write "<BR><BR>"
      sScriptName = Request.ServerVariables("SCRIPT_NAME")

      If iPageNum > 1 Then
         Response.Write " <a class="n" href=" & sScriptName & "?iPageNum="
         Response.Write (iPageNum -1) & "><< Previous</a>"
      End If

      If Not rst.EOF Then
         Response.Write " <a class="n" href=" & sScriptName & "?iPageNum="
         Response.Write (iPageNum +1) & "> Next >></a><BR>"
      Else
         Response.Write "<BR>"
      End If

      Response.Write "Page " & iPageNum

   End Sub

   Sub CleanUp(rst)
      If Not rst Is Nothing then
         If rst.state = adStateOpen then rst.close
         set rst = nothing
      End If
   End Sub

</SCRIPT>

Analyse
Plusieurs points doivent être considérés lorsque vous concevez une solution de pagination :

- Emplacement du curseur. Si vous utilisez un curseur côté client, tous les enregistrements sont lus à chaque ouverture du jeu d'enregistrements. En conséquence, étant donné que tous les enregistrements sont lus, il est rapide d'accéder ultérieurement à la propriété RecordCount ou PageCount. Si vous utilisez un curseur côté serveur, les enregistrements sont extraits lorsque vous en avez besoin. Vous pouvez spécifier le nombre d'enregistrements lus en une fois par la propriété CacheSize pour améliorer les performances. Si vous utilisez cependant les propriétés RecordCount ou PageCount avec un curseur côté serveur, tous les enregistrements sont lus, ce qui annule le gain de performances. Vous devez faire la part des choses entre proposer une interface utilisateur offrant plus d'informations et une navigation plus riche, ou réduire la performance en extrayant tous les enregistrements.
- Lorsque vous utilisez un curseur côté serveur, la propriété CursorType doit être adOpenStatic ou adOpenKeyset pour utiliser la pagination.
- La pagination ne représente pas systématiquement l'interface utilisateur appropriée. De bons scénarios peuvent être des situations dans lesquelles les utilisateurs analysent les résultats depuis un moteur de recherche ou parcourent un catalogue de produits.
- Essayez de trier les enregistrements de façon à ce que les enregistrements plus pertinents apparaissent dans les premières pages (en utilisant par exemple la clause SQL ORDER BY). Les utilisateurs peuvent alors gagner du temps.
- Extrayez uniquement les colonnes à afficher (évitez par exemple SELECT *).
- Extrayez uniquement les enregistrements à afficher. Utilisez des critères de filtrage (utilisez par exemple une clause WHERE).

Vous trouverez ci-après quelques conseils supplémentaires :

- Encapsulez vos valeurs logiques dans des méthodes. L'utilisation de méthodes m'a permis de séparer la logique de présentation de la logique d'accès aux données, ce qui simplifie le portage du code en classes ou composants Windows Script Components ou Visual Basic Scripting Edition (VBScript). Vous facilitez ainsi toute modification des fonctionnalités et améliorez la maintenance du code. Tests et débogages sont également améliorés car les appels de méthode peuvent être commentés et les commentaires annulés.
- Une référence TypeLibrary de ADO est préférable à l'inclusion de ADOVBS.INC, car ASP lit tout le fichier en mémoire lorsqu'il traire les inclusions, et non uniquement ce dont il a besoin.

Conclusion
La pagination est une technique commune utilisée par de nombreuses applications Web pour faciliter la navigation dans un nombre d'enregistrements important. Lorsque vous créez une solution de pagination, vous devez envisager un certain nombre de points, tels la façon dont les enregistrements sont extraits et le type de navigation utilisateur à offrir. Si la meilleure solution dépend de facteurs propres à votre application, le respect des techniques mentionnées dans cet article vous aidera à prendre les meilleurs décisions en matière de conception.

Initialement publié sur MSDN France le 25 avril 2002

 
[ MSDN France pour JDNet
 
Accueil | Haut de page