Partager via


Affichage des résultats d'une requête sous forme de pages

Ce mode d'affichage consiste à retourner les résultats d'une requête sous forme de sous-ensembles, plus petits, de données, aussi appelés pages. Cette façon de procéder est courante lorsqu'il s'agit de présenter à l'utilisateur un affichage des résultats par petits segments, plus faciles à gérer.

Le DataAdapter propose une fonctionnalité permettant de retourner uniquement une page de données, grâce aux surcharges de la méthode Fill. Toutefois, cette solution n'est pas la mieux adaptée lorsque les résultats de la requête sont très volumineux, car, si le DataAdapter remplit le DataTable ou DataSet cible uniquement avec les enregistrements demandés, les ressources sollicitées restent les mêmes que pour retourner l'intégralité de la requête. Pour retourner une page de données provenant d'une source de donnée sans solliciter les ressources requises pour retourner l'intégralité de la requête, spécifiez des critères supplémentaires pour votre requête, afin de limiter le nombre de lignes retournées à celles qui sont requises.

Pour utiliser la méthode Fill afin de retourner une page de données, spécifiez un startRecord, indiquant le premier enregistrement de la page de données, et un maxRecords, indiquant le nombre d'enregistrements de la page de données.

L'exemple de code suivant montre comment utiliser la méthode Fill pour retourner la première page des résultats d'une requête, sachant que la page comptera cinq enregistrements.

Dim currentIndex As Integer = 0
Dim pageSize As Integer = 5

Dim orderSQL As String = "SELECT * FROM Orders ORDER BY OrderID"
Dim myDA As SqlDataAdapter = New SqlDataAdapter(orderSQL, nwindConn)

Dim myDS As DataSet = New DataSet()
myDA.Fill(myDS, currentIndex, pageSize, "Orders")
[C#]
int currentIndex = 0;
int pageSize = 5;

string orderSQL = "SELECT * FROM Orders ORDER BY OrderID";
SqlDataAdapter myDA = new SqlDataAdapter(orderSQL, nwindConn);

DataSet myDS = new DataSet();
myDA.Fill(myDS, currentIndex, pageSize, "Orders");

Dans l'exemple précédent, le DataSet ne reçoit que cinq enregistrements, mais la table Orders est retournée dans son intégralité. Pour remplir le DataSet des cinq même enregistrements, mais en ne retournant que cinq enregistrements, utilisez les clauses TOP et WHERE dans votre instruction SQL, comme dans l'exemple de code suivant.

Dim pageSize As Integer = 5

Dim orderSQL As String = "SELECT TOP " & pageSize & " * FROM Orders ORDER BY OrderID"
Dim myDA As SqlDataAdapter = New SqlDataAdapter(orderSQL, nwindConn)

Dim myDS As DataSet = New DataSet()
myDA.Fill(myDS, "Orders") 
[C#]
int pageSize = 5;

string orderSQL = "SELECT TOP " + pageSize + " * FROM Orders ORDER BY OrderID";
SqlDataAdapter myDA = new SqlDataAdapter(orderSQL, nwindConn);

DataSet myDS = new DataSet();
myDA.Fill(myDS, "Orders");

Notez que, lorsque vous choisissez ce mode d'affichage par pages des résultats d'une requête, vous devez conserver l'identificateur unique en fonction duquel les lignes sont organisées, afin de passer cet identificateur unique à la commande pour retourner la page d'enregistrements suivante, comme le montre l'exemple de code ci-dessous.

Dim lastRecord As String = myDS.Tables("Orders").Rows(pageSize - 1)("OrderID").ToString()
[C#]
string lastRecord = myDS.Tables["Orders"].Rows[pageSize - 1]["OrderID"].ToString();

Pour retourner la page d'enregistrements suivante à l'aide de la surcharge de la méthode Fill qui accepte les paramètres startRecord et maxRecords, incrémentez l'index de l'enregistrement en cours en fonction de la taille de la page (exprimée en nombre d'enregistrements par page) et remplissez la table. N'oubliez pas que le serveur de base de données retourne l'intégralité des résultats de la requête, même si une seule page d'enregistrements est ajoutée au DataSet. Dans l'exemple de code suivant, les lignes de la table sont vidées de leur contenu avant de recevoir la page de données suivante. Vous avez la possibilité de conserver dans un cache local un certain nombre de lignes retournées afin de limiter les sollicitations du serveur de base de données.

currentIndex = currentIndex + pageSize

myDS.Tables("Orders").Rows.Clear()

myDA.Fill(myDS, currentIndex, pageSize, "Orders")
[C#]
currentIndex += pageSize;

myDS.Tables["Orders"].Rows.Clear();

myDA.Fill(myDS, currentIndex, pageSize, "Orders");

Pour retourner la page d'enregistrements suivante sans que le serveur de base de données ne retourne l'intégralité de la requête, spécifiez des critères restrictifs pour l'instruction SQL SELECT. Parce que l'exemple précédent conservait le dernier enregistrement retourné, vous pouvez l'utiliser dans la clause WHERE afin de spécifier le point de départ de la requête, comme le montre l'exemple de code suivant.

orderSQL = "SELECT TOP " & pageSize & " * FROM Orders WHERE OrderID > " & lastRecord & " ORDER BY OrderID"
myDA.SelectCommand.CommandText = orderSQL

myDS.Tables("Orders").Rows.Clear()

myDA.Fill(myDS, "Orders")
[C#]
orderSQL = "SELECT TOP " + pageSize + " * FROM Orders WHERE OrderID > " + lastRecord + " ORDER BY OrderID";
myDA.SelectCommand.CommandText = orderSQL;

myDS.Tables["Orders"].Rows.Clear();

myDA.Fill(myDS, "Orders");

L'exemple qui suit illustre l'affichage des résultats d'une requête sous forme de pages avec spécification de critères dans l'instruction SQL pour ne retourner qu'une page d'enregistrements à la fois à partir de la base de données.

Imports System
Imports System.Data
Imports System.Data.SqlClient
Imports System.Drawing
Imports System.Windows.Forms

Public Class PagingSample
  Inherits Form

  ' Form controls.
  Dim prevBtn As Button = New Button()
  Dim nextBtn As Button = New Button()

  Shared myGrid As DataGrid = New DataGrid()
  Shared pageLbl As Label = New Label()

  ' Paging variables.
  Shared pageSize As Integer = 10      ' Size of viewed page.
  Shared totalPages As Integer = 0    ' Total pages.
  Shared currentPage As Integer = 0    ' Current page.
  Shared firstVisibleCustomer As String = ""  ' First customer on page to determine location for move previous.
  Shared lastVisibleCustomer As String = ""  ' Last customer on page to determine location for move next.

  ' DataSet to bind to DataGrid.
  Shared custTable As DataTable

  ' Initialize connection to database and DataAdapter.
  Shared nwindConn As SqlConnection = New SqlConnection("Data Source=localhost;Integrated Security=SSPI;Initial Catalog=northwind")
  Shared custDA As SqlDataAdapter = New SqlDataAdapter("", nwindConn)
  Shared selCmd As SqlCommand = custDA.SelectCommand()


  Public Shared Sub GetData(direction As String)

    ' Create SQL statement to return a page of records.
    selCmd.Parameters.Clear()

    Select Case direction
      Case "Next"
        selCmd.CommandText = "SELECT TOP " & pageSize & " CustomerID, CompanyName FROM Customers " & _
                       "WHERE CustomerID > @CustomerId ORDER BY CustomerID"
        selCmd.Parameters.Add("@CustomerId", SqlDbType.VarChar, 5).Value = lastVisibleCustomer
      Case "Previous"
        selCmd.CommandText = "SELECT TOP " & pageSize & " CustomerID, CompanyName FROM Customers " & _
                       "WHERE CustomerID < @CustomerId ORDER BY CustomerID DESC"
        selCmd.Parameters.Add("@CustomerId", SqlDbType.VarChar, 5).Value = firstVisibleCustomer
      Case Else
        selCmd.CommandText = "SELECT TOP " & pageSize & " CustomerID, CompanyName FROM Customers ORDER BY CustomerID"
        
        ' Determine total pages.
        Dim totCMD As SqlCommand = New SqlCommand("SELECT Count(*) FROM Customers", nwindConn)
        nwindConn.Open()
        Dim totalRecords As Integer = CInt(totCMD.ExecuteScalar())
        nwindConn.Close()
        totalPages = CInt(Math.Ceiling(CDbl(totalRecords) / pageSize))
    End Select

    ' Fill a temporary table with query results.
    Dim tmpTable As DataTable = New DataTable("Customers")
    Dim recordsAffected As Integer = custDA.Fill(tmpTable)

    ' If table does not exist, create it.
    If custTable Is Nothing Then custTable = tmpTable.Clone()

    ' Refresh table if at least one record returned.
    If recordsAffected > 0 Then
      Select Case direction
        Case "Next"
          currentPage += 1
        Case "Previous"
          currentPage += -1
        Case Else
          currentPage = 1
      End Select

      pageLbl.Text = "Page " & currentPage & " of " & totalPages

      ' Clear rows and add New results.
      custTable.Rows.Clear()

      Dim myRow As DataRow
      For Each myRow In tmpTable.Rows
        custTable.ImportRow(myRow)
      Next

      ' Preserve first and last primary key values.
      Dim ordRows() As DataRow = custTable.Select("", "CustomerID ASC")
      firstVisibleCustomer = ordRows(0)(0).ToString()
      lastVisibleCustomer = ordRows(custTable.Rows.Count - 1)(0).ToString()
    End If
  End Sub


  Public Sub New()
    MyBase.New

    ' Initialize controls and add to form.
    Me.ClientSize = New Size(360, 274)
    Me.Text = "NorthWind Data"

    myGrid.Location = New Point(10,10)
    myGrid.Size = New Size(340, 220)
    myGrid.AllowSorting = true
    myGrid.CaptionText = "NorthWind Customers"
    myGrid.ReadOnly = true
    myGrid.AllowNavigation = false
    myGrid.PreferredColumnWidth = 150

    prevBtn.Text = "<<"
    prevBtn.Size = New Size(48, 24)
    prevBtn.Location = New Point(92, 240)
    AddHandler prevBtn.Click, New EventHandler(AddressOf Prev_OnClick)

    nextBtn.Text = ">>"
    nextBtn.Size = New Size(48, 24)
    nextBtn.Location = New Point(160, 240)

    pageLbl.Text = "No Records Returned."
    pageLbl.Size = New Size(130, 16)
    pageLbl.Location = New Point(218, 244)

    Me.Controls.Add(myGrid)
    Me.Controls.Add(prevBtn)
    Me.Controls.Add(nextBtn)
    Me.Controls.Add(pageLbl)
    AddHandler nextBtn.Click, New EventHandler(AddressOf Next_OnClick)


    ' Populate DataSet with first page of records and bind to grid.
    GetData("Default")
    Dim custDV As DataView = New DataView(custTable, "", "CustomerID", DataViewRowState.CurrentRows)
    myGrid.SetDataBinding(custDV, "")
  End Sub



  Public Shared Sub Prev_OnClick(sender As Object, args As EventArgs)
    GetData("Previous")
  End Sub

  Public Shared Sub Next_OnClick(sender As Object, args As EventArgs)
    GetData("Next")
  End Sub
End Class


Public Class Sample
  Shared Sub Main()
    Application.Run(New PagingSample())
  End Sub
End Class
[C#]
using System;
using System.Data;
using System.Data.SqlClient;
using System.Drawing;
using System.Windows.Forms;

public class PagingSample: Form
{
  // Form controls.
  Button prevBtn = new Button();
  Button nextBtn = new Button();

  static DataGrid myGrid = new DataGrid();
  static Label pageLbl = new Label();

  // Paging variables.
  static int pageSize = 10;      // Size of viewed page.
  static int totalPages = 0;      // Total pages.
  static int currentPage = 0;      // Current page.
  static string firstVisibleCustomer = "";  // First customer on page to determine location for move previous.
  static string lastVisibleCustomer = "";    // Last customer on page to determine location for move next.

  // DataSet to bind to DataGrid.
  static DataTable custTable;

  // Initialize connection to database and DataAdapter.
  static SqlConnection nwindConn = new SqlConnection("Data Source=localhost;Integrated Security=SSPI;Initial Catalog=northwind");
  static SqlDataAdapter custDA = new SqlDataAdapter("", nwindConn);
  static SqlCommand selCmd = custDA.SelectCommand;

  public static void GetData(string direction)
  {
    // Create SQL statement to return a page of records.
    selCmd.Parameters.Clear();

    switch (direction)
    {
      case "Next":
        selCmd.CommandText = "SELECT TOP " + pageSize + " CustomerID, CompanyName FROM Customers " +
                      "WHERE CustomerID > @CustomerId ORDER BY CustomerID";
        selCmd.Parameters.Add("@CustomerId", SqlDbType.VarChar, 5).Value = lastVisibleCustomer;
        break;
      case "Previous":
        selCmd.CommandText = "SELECT TOP " + pageSize + " CustomerID, CompanyName FROM Customers " +
                      "WHERE CustomerID < @CustomerId ORDER BY CustomerID DESC";
        selCmd.Parameters.Add("@CustomerId", SqlDbType.VarChar, 5).Value = firstVisibleCustomer;
        break;
      default:
        selCmd.CommandText = "SELECT TOP " + pageSize + " CustomerID, CompanyName FROM Customers ORDER BY CustomerID";
        
        // Determine total pages.
        SqlCommand totCMD = new SqlCommand("SELECT Count(*) FROM Customers", nwindConn);
        nwindConn.Open();
        int totalRecords = (int)totCMD.ExecuteScalar();
        nwindConn.Close();
        totalPages = (int)Math.Ceiling((double)totalRecords / pageSize);

        break;
    }

    // Fill a temporary table with query results.
    DataTable tmpTable = new DataTable("Customers");
    int recordsAffected = custDA.Fill(tmpTable);

    // If table does not exist, create it.
    if (custTable == null)
      custTable = tmpTable.Clone();

    // Refresh table if at least one record returned.
    if (recordsAffected > 0)
    {
      switch (direction)
      {
        case "Next":
          currentPage++;
          break;
        case "Previous":
          currentPage--;
          break;
        default:
          currentPage = 1;
          break;
      }

      pageLbl.Text = "Page " + currentPage + " of " + totalPages;

      // Clear rows and add new results.
      custTable.Rows.Clear();

      foreach (DataRow myRow in tmpTable.Rows)
        custTable.ImportRow(myRow);

      // Preserve first and last primary key values.
      DataRow[] ordRows = custTable.Select("", "CustomerID ASC");
      firstVisibleCustomer = ordRows[0][0].ToString();
      lastVisibleCustomer = ordRows[custTable.Rows.Count - 1][0].ToString();
    }
  }



  public PagingSample()
  {
    // Initialize controls and add to form.
    this.ClientSize = new Size(360, 274);
    this.Text = "NorthWind Data";

    myGrid.Location = new Point(10,10);
    myGrid.Size = new Size(340, 220);
    myGrid.AllowSorting = true;
    myGrid.CaptionText = "NorthWind Customers";
    myGrid.ReadOnly = true;
    myGrid.AllowNavigation = false;
    myGrid.PreferredColumnWidth = 150;

    prevBtn.Text = "<<";
    prevBtn.Size = new Size(48, 24);
    prevBtn.Location = new Point(92, 240);
    prevBtn.Click += new EventHandler(Prev_OnClick);

    nextBtn.Text = ">>";
    nextBtn.Size = new Size(48, 24);
    nextBtn.Location = new Point(160, 240);

    pageLbl.Text = "No Records Returned.";
    pageLbl.Size = new Size(130, 16);
    pageLbl.Location = new Point(218, 244);

    this.Controls.Add(myGrid);
    this.Controls.Add(prevBtn);
    this.Controls.Add(nextBtn);
    this.Controls.Add(pageLbl);
    nextBtn.Click += new EventHandler(Next_OnClick);


    // Populate DataSet with first page of records and bind to grid.
    GetData("Default");
    DataView custDV = new DataView(custTable, "", "CustomerID", DataViewRowState.CurrentRows);
    myGrid.SetDataBinding(custDV, "");
  }



  public static void Prev_OnClick(object sender, EventArgs args)
  {
    GetData("Previous");
  }

  public static void Next_OnClick(object sender, EventArgs args)
  {
    GetData("Next");
  }
}



public class Sample
{
  static void Main()
  {
    Application.Run(new PagingSample());
  }
}

Voir aussi

Exemples de scénarios ADO.NET | Accès aux données avec ADO.NET | Utilisation des fournisseurs de données .NET Framework pour l'accès aux données | Création et utilisation de DataSets | Création et utilisation de DataTables