Freigeben über


Paging durch ein Abfrageergebnis

Beim Paging durch ein Abfrageergebnis werden die Ergebnisse einer Abfrage in kleineren Untergruppen von Daten oder Seiten zurückgegeben. Dies ist eine allgemein übliche Vorgehensweise, um einem Benutzer Ergebnisse in kleinen Stücken anzuzeigen, die sich leicht verwalten lassen.

Der DataAdapter stellt eine Funktion bereit, mit der durch Überladungen der Fill-Methode immer nur eine Seite mit Daten zurückgegeben wird. Dies ist möglicherweise jedoch nicht die beste Methode, wenn Benutzer umfangreiche Abfrageergebnisse durchgehen müssen. Dies liegt daran, dass die Ressourcen zum Zurückgeben der gesamten Abfrage noch verwendet werden, während der DataAdapter das Ziel (DataTable oder DataSet) nur mit den angeforderten Datensätzen füllt. Geben Sie zusätzliche Kriterien für Ihre Abfrage ein, um eine Seite mit Daten von einer Datenquelle ohne die Ressourcen zurückzugeben, die zum Zurückgeben der gesamten Abfrage erforderlich sind, so dass nur die erforderlichen Zeilen zurückgegeben werden.

Wenn Sie die Fill-Methode zum Zurückgeben einer Seite mit Daten verwenden möchten, geben Sie den startRecord-Parameter an, der den ersten Datensatz in der Seite mit Daten angibt, sowie den maxRecords-Parameter, der die Anzahl der Datensätze in der Seite mit Daten festlegt.

Das folgende Codebeispiel zeigt, wie mit der Fill-Methode die erste Seite mit fünf Datensätzen eines Abfrageergebnisses zurückgegeben wird.

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");

Im vorhergehenden Beispiel wird das DataSet nur mit fünf Datensätzen gefüllt, obwohl die gesamte Orders-Tabelle zurückgegeben wird. Verwenden Sie die Klauseln TOP und WHERE in Ihrer SQL-Anweisung wie im folgenden Beispiel gezeigt, um das DataSet mit diesen fünf Datensätzen zu füllen, aber nur fünf Datensätze zurückzugeben.

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");

Wenn Sie die Abfrageergebnisse auf diese Weise durchgehen, müssen Sie den eindeutigen Bezeichner, nach dem die Zeilen geordnet sind, beibehalten, um die eindeutige ID an den Befehl zu übergeben und die nächste Seite mit Datensätzen zurückzugeben (siehe folgendes Codebeispiel).

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

Wenn Sie die nächste Seite mit Datensätzen durch Überladen der Fill-Methode mit den Parametern startRecord und maxRecords zurückgeben möchten, müssen Sie den aktuellen Datensatzindex um die Seitengröße erhöhen und die Tabelle füllen. Vergessen Sie nicht, dass der Datenbankserver alle Abfrageergebnisse zurückgibt, selbst wenn nur eine Seite mit Datensätzen zum DataSet hinzugefügt wird. Im folgenden Codebeispiel wird der Inhalt der Tabellenzeilen gelöscht, bevor sie mit der nächsten Seite mit Daten gefüllt werden. Möglicherweise soll eine bestimmte Anzahl zurückgegebener Zeilen in einem lokalen Cache beibehalten werden, um die Anzahl der Schleifen zum Datenbankserver zu reduzieren.

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");

Geben Sie restriktive Kriterien für die SQL-Anweisung SELECT an, um die nächste Seite mit Datensätzen zurückzugeben, ohne dass der Datenbankserver die ganze Abfrage zurückgeben muss. Da im vorhergehenden Beispiel der zuletzt zurückgegebene Datensatz beibehalten wurde, können Sie ihn in der WHERE-Klausel verwenden, um – wie im folgenden Codebeispiel gezeigt – einen Ausgangspunkt für die Abfrage anzugeben.

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");

Im folgenden Beispiel wird durch Angabe von Kriterien in der SQL-Anweisung durch ein Abfrageergebnis gegangen, indem immer nur jeweils eine Seite mit Datensätzen aus der Datenbank zurückgegeben wird.

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());
  }
}

Siehe auch

Beispielszenarien zu ADO.NET | Zugreifen auf Daten mit ADO.NET | Datenzugriff mit .NET Framework-Datenprovidern | Erstellen und Verwenden von DataSets | Erstellen und Verwenden von Datentabellen