Bagikan melalui


Paging Secara Efisien Melalui Data Dalam Jumlah Besar (C#)

oleh Scott Mitchell

Unduh PDF

Opsi halaman default kontrol presentasi data tidak cocok saat bekerja dengan data dalam jumlah besar, karena kontrol sumber data yang mendasar mengambil semua rekaman, meskipun hanya subkumpulan data yang ditampilkan. Dalam keadaan seperti itu, kita harus beralih ke halaman kustom.

Pendahuluan

Seperti yang kita bahas dalam tutorial sebelumnya, penomor dapat diimplementasikan dengan salah satu dari dua cara:

  • Halaman Default dapat diimplementasikan hanya dengan memeriksa opsi Aktifkan Halaman di tag pintar kontrol Web data; namun, setiap kali melihat halaman data, ObjectDataSource mengambil semua rekaman, meskipun hanya subset yang ditampilkan di halaman
  • Halaman Kustom meningkatkan performa halaman default dengan mengambil hanya rekaman dari database yang perlu ditampilkan untuk halaman data tertentu yang diminta oleh pengguna; namun, penomor kustom melibatkan sedikit lebih banyak upaya untuk diterapkan daripada penomor default

Karena kemudahan implementasi, periksa kotak centang dan Anda selesai! halaman default adalah opsi yang menarik. Pendekatan naifnya dalam mengambil semua catatan, meskipun, menjadikannya pilihan yang tidak masuk akal ketika penomoran melalui data dalam jumlah yang cukup besar atau untuk situs dengan banyak pengguna bersamaan. Dalam keadaan seperti itu, kita harus beralih ke halaman kustom untuk menyediakan sistem yang responsif.

Tantangan penomor kustom adalah dapat menulis kueri yang mengembalikan kumpulan rekaman yang tepat yang diperlukan untuk halaman data tertentu. Untungnya, Microsoft SQL Server 2005 menyediakan kata kunci baru untuk hasil peringkat, yang memungkinkan kami menulis kueri yang dapat mengambil subset rekaman yang tepat secara efisien. Dalam tutorial ini kita akan melihat cara menggunakan kata kunci SQL Server 2005 baru ini untuk mengimplementasikan halaman kustom dalam kontrol GridView. Meskipun antarmuka pengguna untuk penomor kustom identik dengan itu untuk halaman default, melangkah dari satu halaman ke halaman berikutnya menggunakan halaman kustom bisa menjadi beberapa urutan besarnya lebih cepat daripada halaman default.

Catatan

Perolehan performa yang tepat dipamerkan oleh penomoran halaman kustom tergantung pada jumlah total rekaman yang dipatuhi dan beban yang ditempatkan di server database. Di akhir tutorial ini kita akan melihat beberapa metrik kasar yang menampilkan manfaat dalam performa yang diperoleh melalui penomor kustom.

Langkah 1: Memahami Proses Halaman Kustom

Saat penomoran melalui data, rekaman yang tepat ditampilkan di halaman bergantung pada halaman data yang diminta dan jumlah rekaman yang ditampilkan per halaman. Misalnya, bayangkan bahwa kami ingin halaman melalui 81 produk, menampilkan 10 produk per halaman. Saat melihat halaman pertama, kami menginginkan produk 1 hingga 10; ketika melihat halaman kedua kita akan tertarik pada produk 11 hingga 20, dan sebagainya.

Ada tiga variabel yang menentukan rekaman apa yang perlu diambil dan bagaimana antarmuka halaman harus dirender:

  • Indeks Baris Mulai indeks baris pertama di halaman data yang akan ditampilkan; indeks ini dapat dihitung dengan mengalikan indeks halaman dengan rekaman yang akan ditampilkan per halaman dan menambahkannya. Misalnya, saat halaman melalui rekaman 10 per satu, untuk halaman pertama (yang indeks halamannya adalah 0), Indeks Baris Mulai adalah 0 * 10 + 1, atau 1; untuk halaman kedua (yang indeks halamannya adalah 1), Indeks Baris Mulai adalah 1 * 10 + 1, atau 11.
  • Baris Maksimum jumlah maksimum rekaman yang akan ditampilkan per halaman. Variabel ini disebut sebagai baris maksimum karena untuk halaman terakhir mungkin ada lebih sedikit rekaman yang dikembalikan daripada ukuran halaman. Misalnya, ketika halaman melalui 81 produk 10 rekaman per halaman, halaman kesembilan dan terakhir hanya akan memiliki satu catatan. Namun, tidak ada halaman yang akan menampilkan lebih banyak rekaman daripada nilai Baris Maksimum.
  • Total Catatan Menghitung jumlah total rekaman yang di-paged through. Meskipun variabel ini tidak diperlukan untuk menentukan rekaman apa yang akan diambil untuk halaman tertentu, variabel ini menentukan antarmuka halaman. Misalnya, jika ada 81 produk yang di-paged through, antarmuka paging tahu untuk menampilkan sembilan nomor halaman di antarmuka pengguna halaman.

Dengan halaman default, Indeks Baris Mulai dihitung sebagai produk indeks halaman dan ukuran halaman ditambah satu, sedangkan Baris Maksimum hanyalah ukuran halaman. Karena halaman default mengambil semua rekaman dari database saat merender halaman data apa pun, indeks untuk setiap baris diketahui, sehingga membuat pemindahan ke baris Indeks Baris Mulai menjadi tugas sepele. Selain itu, Jumlah Rekaman Total tersedia dengan mudah, karena hanya jumlah rekaman dalam DataTable (atau objek apa pun yang digunakan untuk menyimpan hasil database).

Mengingat variabel Indeks Baris Mulai dan Baris Maksimum, implementasi penomoran halaman kustom hanya boleh mengembalikan subset rekaman yang tepat yang dimulai pada Indeks Baris Mulai dan hingga Jumlah Baris Maksimum dari rekaman setelah itu. Penomor kustom memberikan dua tantangan:

  • Kita harus dapat mengaitkan indeks baris secara efisien dengan setiap baris di seluruh data yang di-paged through sehingga kita dapat mulai mengembalikan rekaman pada Indeks Baris Mulai yang ditentukan
  • Kita perlu menyediakan jumlah total rekaman yang di-paged through

Dalam dua langkah berikutnya kita akan memeriksa skrip SQL yang diperlukan untuk merespons kedua tantangan ini. Selain skrip SQL, kita juga perlu menerapkan metode di DAL dan BLL.

Langkah 2: Mengembalikan Jumlah Total Rekaman yang Di-Paged Through

Sebelum kita memeriksa cara mengambil subset rekaman yang tepat untuk halaman yang ditampilkan, mari kita lihat terlebih dahulu cara mengembalikan jumlah total rekaman yang di-paged through. Informasi ini diperlukan untuk mengonfigurasi antarmuka pengguna halaman dengan benar. Jumlah total rekaman yang dikembalikan oleh kueri SQL tertentu dapat diperoleh dengan menggunakan COUNT fungsi agregat. Misalnya, untuk menentukan jumlah total rekaman dalam Products tabel, kita bisa menggunakan kueri berikut:

SELECT COUNT(*)
FROM Products

Mari kita tambahkan metode ke DAL kita yang mengembalikan informasi ini. Secara khusus, kita akan membuat metode DAL yang disebut TotalNumberOfProducts() yang menjalankan pernyataan yang ditunjukkan SELECT di atas.

Mulailah dengan membuka file Himpunan Northwind.xsd Data Yang Dititik di App_Code/DAL folder . Selanjutnya, klik kanan pada ProductsTableAdapter di Perancang dan pilih Tambahkan Kueri. Seperti yang telah kita lihat dalam tutorial sebelumnya, ini akan memungkinkan kita untuk menambahkan metode baru ke DAL yang, ketika dipanggil, akan menjalankan pernyataan SQL tertentu atau prosedur tersimpan. Seperti metode TableAdapter kami dalam tutorial sebelumnya, untuk yang satu ini memilih untuk menggunakan pernyataan SQL ad-hoc.

Menggunakan Pernyataan Ad-Hoc SQL

Gambar 1: Menggunakan Pernyataan Ad-Hoc SQL

Pada layar berikutnya kita dapat menentukan jenis kueri apa yang akan dibuat. Karena kueri ini akan mengembalikan satu, nilai skalar jumlah total rekaman dalam Products tabel memilih SELECT opsi yang mengembalikan nilai singe.

Mengonfigurasi Kueri untuk Menggunakan Pernyataan SELECT yang Mengembalikan Nilai Tunggal

Gambar 2: Mengonfigurasi Kueri untuk Menggunakan Pernyataan SELECT yang Mengembalikan Nilai Tunggal

Setelah menunjukkan jenis kueri yang akan digunakan, selanjutnya kita harus menentukan kueri.

Menggunakan SELECT COUNT(*) FROM Products Query

Gambar 3: Gunakan KUERI SELECT COUNT(*) FROM Products

Terakhir, tentukan nama untuk metode . Seperti yang disebutkan di dalamnya, mari kita gunakan TotalNumberOfProducts.

Beri nama Metode DAL TotalNumberOfProducts

Gambar 4: Beri nama Metode DAL TotalNumberOfProducts

Setelah mengklik Selesai, wizard akan menambahkan TotalNumberOfProducts metode ke DAL. Metode pengembalian skalar dalam DAL mengembalikan jenis nullable, jika hasil dari kueri SQL adalah NULL. Kueri kami COUNT , bagaimanapun, akan selalu mengembalikan nilai nonNULL ; terlepas dari itu, metode DAL mengembalikan bilangan bulat null.

Selain metode DAL, kita juga membutuhkan metode di BLL. ProductsBLL Buka file kelas dan tambahkan TotalNumberOfProducts metode yang hanya memanggil ke metode DAL sTotalNumberOfProducts:

public int TotalNumberOfProducts()
{
    return Adapter.TotalNumberOfProducts().GetValueOrDefault();
}

Metode DAL s TotalNumberOfProducts mengembalikan bilangan bulat null; namun, kami telah membuat ProductsBLL metode kelas s TotalNumberOfProducts sehingga mengembalikan bilangan bulat standar. Oleh karena itu, kita harus memiliki ProductsBLL metode kelas s TotalNumberOfProducts mengembalikan bagian nilai dari bilangan bulat null yang dikembalikan oleh metode DAL s TotalNumberOfProducts . Panggilan untuk GetValueOrDefault() mengembalikan nilai bilangan bulat null, jika ada; jika bilangan bulat null adalah null, namun, nilai bilangan bulat default, 0.

Langkah 3: Mengembalikan Subset Rekaman yang Tepat

Tugas kami berikutnya adalah membuat metode di DAL dan BLL yang menerima variabel Indeks Baris Mulai dan Baris Maksimum yang dibahas sebelumnya dan mengembalikan rekaman yang sesuai. Sebelum kita melakukannya, mari kita lihat terlebih dahulu skrip SQL yang diperlukan. Tantangan yang dihadapi kita adalah bahwa kita harus dapat menetapkan indeks secara efisien ke setiap baris di seluruh hasil yang di-paged through sehingga kita dapat mengembalikan hanya rekaman tersebut yang dimulai di Indeks Baris Mulai (dan hingga jumlah rekaman Rekaman Maksimum).

Ini bukan tantangan jika sudah ada kolom dalam tabel database yang berfungsi sebagai indeks baris. Pada pandangan pertama kita mungkin berpikir bahwa Products bidang tabel ProductID sudah cukup, karena produk pertama memiliki ProductID 1, yang kedua 2, dan sebagainya. Namun, menghapus produk meninggalkan celah dalam urutan, membatalkan pendekatan ini.

Ada dua teknik umum yang digunakan untuk mengaitkan indeks baris secara efisien dengan data ke halaman, sehingga memungkinkan subset rekaman yang tepat untuk diambil:

  • ROW_NUMBER() SQL Server 2005 s baru ke SQL Server 2005, ROW_NUMBER() kata kunci mengaitkan peringkat dengan setiap rekaman yang dikembalikan berdasarkan beberapa pemesanan. Peringkat ini dapat digunakan sebagai indeks baris untuk setiap baris.

  • Menggunakan variabel tabel dan SET ROWCOUNT pernyataanSET ROWCOUNT digunakan untuk menentukan berapa banyak total rekaman yang harus diproses kueri sebelum mengakhiri; variabel tabel adalah variabel T-SQL lokal yang dapat menyimpan data tabular, mirip dengan tabel sementara. Pendekatan ini bekerja sama baiknya dengan Microsoft SQL Server 2005 dan SQL Server 2000 (sedangkan ROW_NUMBER() pendekatan hanya berfungsi dengan SQL Server 2005).

    Idenya di sini adalah membuat variabel tabel yang memiliki IDENTITY kolom dan kolom untuk kunci utama tabel yang datanya sedang di-paged through. Selanjutnya, konten tabel yang datanya sedang di-paged through dibuang ke dalam variabel tabel, sehingga mengaitkan indeks baris berurutan (melalui IDENTITY kolom) untuk setiap rekaman dalam tabel. Setelah variabel tabel diisi, SELECT pernyataan pada variabel tabel, digabungkan dengan tabel yang mendasarinya, dapat dijalankan untuk menarik keluar rekaman tertentu. Pernyataan SET ROWCOUNT ini digunakan untuk secara cerdas membatasi jumlah rekaman yang perlu dibuang ke dalam variabel tabel.

    Efisiensi pendekatan ini didasarkan pada nomor halaman yang diminta, karena SET ROWCOUNT nilai ditetapkan nilai Indeks Baris Mulai ditambah Baris Maksimum. Ketika penomoran melalui halaman bernomor rendah seperti beberapa halaman pertama data, pendekatan ini sangat efisien. Namun, ini menunjukkan performa seperti halaman default saat mengambil halaman di dekat akhir.

Tutorial ini mengimplementasikan penomor kustom menggunakan ROW_NUMBER() kata kunci. Untuk informasi selengkapnya tentang menggunakan variabel dan SET ROWCOUNT teknik tabel, lihat Paging Secara Efisien Melalui Data Dalam Jumlah Besar.

Kata ROW_NUMBER() kunci yang terkait dengan peringkat dengan setiap rekaman yang dikembalikan melalui pengurutan tertentu menggunakan sintaks berikut:

SELECT columnList,
       ROW_NUMBER() OVER(orderByClause)
FROM TableName

ROW_NUMBER() mengembalikan nilai numerik yang menentukan peringkat untuk setiap rekaman sehubungan dengan pengurutan yang ditunjukkan. Misalnya, untuk melihat peringkat untuk setiap produk, diurutkan dari yang paling mahal hingga yang paling murah, kita dapat menggunakan kueri berikut:

SELECT ProductName, UnitPrice,
       ROW_NUMBER() OVER(ORDER BY UnitPrice DESC) AS PriceRank
FROM Products

Gambar 5 memperlihatkan hasil kueri ini saat dijalankan melalui jendela kueri di Visual Studio. Perhatikan bahwa produk dipesan berdasarkan harga, bersama dengan peringkat harga untuk setiap baris.

Peringkat Harga Disertakan untuk Setiap Rekaman yang Dikembalikan

Gambar 5: Peringkat Harga Disertakan untuk Setiap Rekaman yang Dikembalikan

Catatan

ROW_NUMBER() hanyalah salah satu dari banyak fungsi peringkat baru yang tersedia di SQL Server 2005. Untuk diskusi yang lebih menyeluruh tentang ROW_NUMBER(), bersama dengan fungsi peringkat lainnya, baca Mengembalikan Hasil Berpangkat dengan Microsoft SQL Server 2005.

Saat memberi peringkat hasil berdasarkan kolom yang ditentukan ORDER BY dalam OVER klausa (UnitPrice, dalam contoh di atas), SQL Server harus mengurutkan hasilnya. Ini adalah operasi cepat jika ada indeks berkluster di atas kolom hasil yang diurutkan oleh, atau jika ada indeks yang mencakup, tetapi bisa lebih mahal jika tidak. Untuk membantu meningkatkan performa untuk kueri yang cukup besar, pertimbangkan untuk menambahkan indeks non-kluster untuk kolom tempat hasil diurutkan. Lihat Fungsi dan Performa Peringkat di SQL Server 2005 untuk melihat pertimbangan performa yang lebih rinci.

Informasi peringkat yang dikembalikan oleh ROW_NUMBER() tidak dapat langsung digunakan dalam WHERE klausa. Namun, tabel turunan dapat digunakan untuk mengembalikan hasilnya ROW_NUMBER() , yang kemudian dapat muncul dalam WHERE klausa. Misalnya, kueri berikut menggunakan tabel turunan untuk mengembalikan kolom ProductName dan UnitPrice, bersama dengan ROW_NUMBER() hasilnya, lalu menggunakan klausul WHERE untuk hanya mengembalikan produk yang peringkat harganya antara 11 dan 20:

SELECT PriceRank, ProductName, UnitPrice
FROM
   (SELECT ProductName, UnitPrice,
       ROW_NUMBER() OVER(ORDER BY UnitPrice DESC) AS PriceRank
    FROM Products
   ) AS ProductsWithRowNumber
WHERE PriceRank BETWEEN 11 AND 20

Memperluas konsep ini sedikit lebih jauh, kita dapat menggunakan pendekatan ini untuk mengambil halaman data tertentu mengingat nilai Indeks Baris Mulai dan Baris Maksimum yang diinginkan:

SELECT PriceRank, ProductName, UnitPrice
FROM
   (SELECT ProductName, UnitPrice,
       ROW_NUMBER() OVER(ORDER BY UnitPrice DESC) AS PriceRank
    FROM Products
   ) AS ProductsWithRowNumber
WHERE PriceRank > <i>StartRowIndex</i> AND
    PriceRank <= (<i>StartRowIndex</i> + <i>MaximumRows</i>)

Catatan

Seperti yang akan kita lihat nanti dalam tutorial ini, StartRowIndex yang disediakan oleh ObjectDataSource diindeks mulai dari nol, sedangkan nilai yang ROW_NUMBER() dikembalikan oleh SQL Server 2005 diindeks mulai dari 1. Oleh karena itu, WHERE klausul mengembalikan rekaman tersebut di mana PriceRank secara ketat lebih besar dari StartRowIndex dan kurang dari atau sama dengan StartRowIndex + MaximumRows.

Sekarang setelah kita membahas bagaimana ROW_NUMBER() dapat digunakan untuk mengambil halaman data tertentu mengingat nilai Indeks Baris Mulai dan Baris Maksimum, kita sekarang perlu menerapkan logika ini sebagai metode dalam DAL dan BLL.

Saat membuat kueri ini, kita harus memutuskan urutan di mana hasilnya akan diberi peringkat; mari kita urutkan produk berdasarkan namanya dalam urutan alfabet. Ini berarti bahwa dengan implementasi penomoran halaman kustom dalam tutorial ini kita tidak akan dapat membuat laporan halaman kustom daripada yang juga dapat diurutkan. Namun, dalam tutorial berikutnya, kita akan melihat bagaimana fungsionalitas tersebut dapat disediakan.

Di bagian sebelumnya kami membuat metode DAL sebagai pernyataan SQL ad-hoc. Sayangnya, pengurai T-SQL di Visual Studio yang digunakan oleh wizard TableAdapter tidak menyukai sintaks yang OVER digunakan oleh ROW_NUMBER() fungsi . Oleh karena itu, kita harus membuat metode DAL ini sebagai prosedur tersimpan. Pilih Penjelajah Server dari menu Tampilan (atau tekan Ctrl+Alt+S) dan perluas simpul NORTHWND.MDF . Untuk menambahkan prosedur tersimpan baru, klik kanan pada simpul Prosedur Tersimpan dan pilih Tambahkan Prosedur Tersimpan Baru (lihat Gambar 6).

Menambahkan Prosedur Tersimpan Baru untuk Halaman Melalui Produk

Gambar 6: Tambahkan Prosedur Tersimpan Baru untuk Paging Melalui Produk

Prosedur tersimpan ini harus menerima dua parameter input bilangan bulat - dan dan menggunakan @startRowIndex fungsi yang diurutkan oleh @maximumRows bidang , hanya mengembalikan baris yang lebih besar dari yang ditentukan ROW_NUMBER() dan kurang dari atau sama dengan ProductName@startRowIndex@startRowIndex s. + @maximumRow Masukkan skrip berikut ke dalam prosedur tersimpan baru lalu klik ikon Simpan untuk menambahkan prosedur tersimpan ke database.

CREATE PROCEDURE dbo.GetProductsPaged
(
    @startRowIndex int,
    @maximumRows int
)
AS
    SELECT     ProductID, ProductName, SupplierID, CategoryID, QuantityPerUnit,
               UnitPrice, UnitsInStock, UnitsOnOrder, ReorderLevel, Discontinued,
               CategoryName, SupplierName
FROM
   (
       SELECT ProductID, ProductName, SupplierID, CategoryID, QuantityPerUnit,
              UnitPrice, UnitsInStock, UnitsOnOrder, ReorderLevel, Discontinued,
              (SELECT CategoryName
               FROM Categories
               WHERE Categories.CategoryID = Products.CategoryID) AS CategoryName,
              (SELECT CompanyName
               FROM Suppliers
               WHERE Suppliers.SupplierID = Products.SupplierID) AS SupplierName,
              ROW_NUMBER() OVER (ORDER BY ProductName) AS RowRank
        FROM Products
    ) AS ProductsWithRowNumbers
WHERE RowRank > @startRowIndex AND RowRank <= (@startRowIndex + @maximumRows)

Setelah membuat prosedur tersimpan, luangkan waktu sejenak untuk mengujinya. Klik kanan pada GetProductsPaged nama prosedur tersimpan di Server Explorer dan pilih opsi Jalankan. Visual Studio kemudian akan meminta parameter input, @startRowIndex dan @maximumRow s (lihat Gambar 7). Coba nilai yang berbeda dan periksa hasilnya.

Masukkan Nilai untuk kelas <span= @startRowIndex dan @maximumRows Parameter" />

Gambar 7: Masukkan Nilai untuk @startRowIndex parameter dan @maximumRows

Setelah memilih nilai parameter input ini, jendela Output akan menampilkan hasilnya. Gambar 8 menunjukkan hasil saat meneruskan 10 untuk @startRowIndex parameter dan @maximumRows .

Rekaman yang Akan Muncul di Halaman Kedua Data dikembalikan

Gambar 8: Rekaman yang Akan Muncul di Halaman Kedua Data dikembalikan (Klik untuk melihat gambar ukuran penuh)

Dengan prosedur tersimpan ini dibuat, kami siap untuk membuat ProductsTableAdapter metode . Buka Himpunan Northwind.xsd Data Yang Dititik, klik kanan di ProductsTableAdapter, dan pilih opsi Tambahkan Kueri. Alih-alih membuat kueri menggunakan pernyataan SQL ad-hoc, buat menggunakan prosedur tersimpan yang ada.

Membuat Metode DAL Menggunakan Prosedur Tersimpan yang Ada

Gambar 9: Buat Metode DAL Menggunakan Prosedur Tersimpan yang Ada

Selanjutnya, kami diminta untuk memilih prosedur tersimpan yang akan dipanggil. Pilih prosedur tersimpan GetProductsPaged dari daftar drop-down.

Pilih Prosedur Tersimpan GetProductsPaged dari Daftar Drop-Down

Gambar 10: Pilih Prosedur Tersimpan GetProductsPaged dari Daftar Drop-Down

Layar berikutnya kemudian menanyakan jenis data apa yang dikembalikan oleh prosedur tersimpan: data tabular, satu nilai, atau tanpa nilai. Karena prosedur tersimpan GetProductsPaged dapat mengembalikan beberapa rekaman, menunjukkan bahwa ia mengembalikan data tabular.

Menunjukkan bahwa Prosedur Tersimpan Mengembalikan Data Tabular

Gambar 11: Menunjukkan bahwa Prosedur Tersimpan Mengembalikan Data Tabular

Terakhir, tunjukkan nama metode yang ingin Anda buat. Seperti tutorial kami sebelumnya, lanjutkan dan buat metode menggunakan Isi DataTable dan Kembalikan DataTable. Beri nama metode FillPaged pertama dan yang kedua GetProductsPaged.

Beri nama Metode FillPaged dan GetProductsPaged

Gambar 12: Beri Nama Metode FillPaged dan GetProductsPaged

Selain membuat metode DAL untuk mengembalikan halaman produk tertentu, kita juga perlu menyediakan fungsionalitas tersebut di BLL. Seperti metode DAL, metode GetProductsPaged BLL harus menerima dua input bilangan bulat untuk menentukan Indeks Baris Mulai dan Baris Maksimum, dan harus mengembalikan hanya rekaman yang termasuk dalam rentang yang ditentukan. Buat metode BLL seperti itu di kelas ProductsBLL yang hanya memanggil ke dalam metode GetProductsPaged DAL, seperti:

[System.ComponentModel.DataObjectMethodAttribute(
    System.ComponentModel.DataObjectMethodType.Select, false)]
public Northwind.ProductsDataTable GetProductsPaged(int startRowIndex, int maximumRows)
{
    return Adapter.GetProductsPaged(startRowIndex, maximumRows);
}

Anda dapat menggunakan nama apa pun untuk parameter input metode BLL, tetapi, seperti yang akan kita lihat segera, memilih untuk menggunakan startRowIndex dan maximumRows menyimpan kami dari sedikit pekerjaan tambahan saat mengonfigurasi ObjectDataSource untuk menggunakan metode ini.

Langkah 4: Mengonfigurasi ObjectDataSource untuk Menggunakan Halaman Kustom

Dengan metode BLL dan DAL untuk mengakses subset rekaman tertentu selesai, kami siap untuk membuat kontrol GridView yang halaman melalui rekaman yang mendasarnya menggunakan halaman kustom. Mulailah dengan membuka EfficientPaging.aspx halaman di PagingAndSorting folder, tambahkan GridView ke halaman, dan konfigurasikan untuk menggunakan kontrol ObjectDataSource baru. Dalam tutorial kami sebelumnya, kami sering memiliki ObjectDataSource yang dikonfigurasi untuk menggunakan ProductsBLL metode kelas s GetProducts . Namun, kali ini, kita ingin menggunakan metode sebagai gantinya GetProductsPaged , karena GetProducts metode mengembalikan semua produk dalam database sedangkan GetProductsPaged hanya mengembalikan subset rekaman tertentu.

Mengonfigurasi ObjectDataSource untuk Menggunakan Metode GetProductsPaged Kelas ProductsBLL

Gambar 13: Konfigurasikan ObjectDataSource untuk Menggunakan Metode GetProductsPaged Kelas ProductsBLL

Karena kita membuat GridView baca-saja, luangkan waktu sejenak untuk mengatur daftar drop-down metode di tab INSERT, UPDATE, dan DELETE ke (None).

Selanjutnya, wizard ObjectDataSource meminta sumber GetProductsPaged metode dan startRowIndexmaximumRows nilai parameter input. Parameter input ini sebenarnya akan diatur oleh GridView secara otomatis, jadi cukup biarkan sumber diatur ke Tidak Ada dan klik Selesai.

Biarkan Sumber Parameter Input sebagai Tidak Ada

Gambar 14: Biarkan Sumber Parameter Input sebagai Tidak Ada

Setelah menyelesaikan wizard ObjectDataSource, GridView akan berisi BoundField atau CheckBoxField untuk setiap bidang data produk. Jangan ragu untuk menyesuaikan tampilan GridView sesuai keinginan Anda. Saya telah memilih untuk hanya ProductNamemenampilkan , , CategoryName, SupplierNameQuantityPerUnit, dan UnitPrice BoundFields. Selain itu, konfigurasikan GridView untuk mendukung halaman dengan mencentang kotak centang Aktifkan Halaman di tag pintarnya. Setelah perubahan ini, markup deklaratif GridView dan ObjectDataSource akan terlihat mirip dengan yang berikut ini:

<asp:GridView ID="GridView1" runat="server" AutoGenerateColumns="False"
    DataKeyNames="ProductID" DataSourceID="ObjectDataSource1" AllowPaging="True">
    <Columns>
        <asp:BoundField DataField="ProductName" HeaderText="Product"
            SortExpression="ProductName" />
        <asp:BoundField DataField="CategoryName" HeaderText="Category"
            ReadOnly="True" SortExpression="CategoryName" />
        <asp:BoundField DataField="SupplierName" HeaderText="Supplier"
            SortExpression="SupplierName" />
        <asp:BoundField DataField="QuantityPerUnit" HeaderText="Qty/Unit"
            SortExpression="QuantityPerUnit" />
        <asp:BoundField DataField="UnitPrice" DataFormatString="{0:c}"
            HeaderText="Price" HtmlEncode="False" SortExpression="UnitPrice" />
    </Columns>
</asp:GridView>
<asp:ObjectDataSource ID="ObjectDataSource1" runat="server"
    OldValuesParameterFormatString="original_{0}" SelectMethod="GetProductsPaged"
    TypeName="ProductsBLL">
    <SelectParameters>
        <asp:Parameter Name="startRowIndex" Type="Int32" />
        <asp:Parameter Name="maximumRows" Type="Int32" />
    </SelectParameters>
</asp:ObjectDataSource>

Namun, jika Anda mengunjungi halaman melalui browser, GridView bukanlah tempat untuk ditemukan.

GridView Tidak Ditampilkan

Gambar 15: GridView Tidak Ditampilkan

GridView hilang karena ObjectDataSource saat ini menggunakan 0 sebagai nilai untuk GetProductsPagedstartRowIndex parameter input dan maximumRows . Oleh karena itu, kueri SQL yang dihasilkan tidak mengembalikan rekaman dan oleh karena itu GridView tidak ditampilkan.

Untuk memperbaikinya, kita perlu mengonfigurasi ObjectDataSource untuk menggunakan halaman kustom. Ini dapat dicapai dalam langkah-langkah berikut:

  1. Atur properti ObjectDataSource EnablePaging ke true ini menunjukkan ke ObjectDataSource bahwa properti tersebut harus diteruskan ke SelectMethod dua parameter tambahan: satu untuk menentukan Indeks Baris Mulai (StartRowIndexParameterName), dan satu untuk menentukan Baris Maksimum (MaximumRowsParameterName).
  2. Atur ObjectDataSource s StartRowIndexParameterName dan MaximumRowsParameterName Properti Sesuai denganStartRowIndexParameterName properti dan MaximumRowsParameterName menunjukkan nama parameter input yang SelectMethod diteruskan ke untuk tujuan penomoran kustom. Secara default, nama parameter ini adalah startIndexRow dan maximumRows, itulah sebabnya, saat membuat GetProductsPaged metode di BLL, saya menggunakan nilai-nilai ini untuk parameter input. Jika Anda memilih untuk menggunakan nama parameter yang berbeda untuk metode BLL s seperti dan , misalnya Anda perlu mengatur Properti dan GetProductsPaged ObjectDataSource yang startIndex sesuai (seperti startIndex untuk maxRows dan maxRows untuk StartRowIndexParameterName).MaximumRowsParameterNameStartRowIndexParameterNameMaximumRowsParameterName
  3. Atur Properti ObjectDataSource keSelectCountMethodNama Metode yang Mengembalikan Jumlah Total Rekaman yang Di-Paged Through (TotalNumberOfProducts) mengingat bahwa ProductsBLL metode kelas s TotalNumberOfProducts mengembalikan jumlah total rekaman yang di-paged melalui menggunakan metode DAL yang menjalankan SELECT COUNT(*) FROM Products kueri. Informasi ini diperlukan oleh ObjectDataSource untuk merender antarmuka halaman dengan benar.
  4. startRowIndex Hapus elemen dan maximumRows<asp:Parameter> dari ObjectDataSource s Declarative Markup saat mengonfigurasi ObjectDataSource melalui wizard, Visual Studio secara otomatis menambahkan dua <asp:Parameter> elemen untuk GetProductsPaged parameter input metode s. Dengan mengatur EnablePaging ke true, parameter ini akan diteruskan secara otomatis; jika parameter juga muncul dalam sintaks deklaratif, ObjectDataSource akan mencoba meneruskan empat parameter ke GetProductsPaged metode dan dua parameter ke metode .TotalNumberOfProducts Jika Anda lupa menghapus elemen-elemen ini <asp:Parameter> , saat mengunjungi halaman melalui browser, Anda akan mendapatkan pesan kesalahan seperti: ObjectDataSource 'ObjectDataSource1' tidak dapat menemukan metode non-generik 'TotalNumberOfProducts' yang memiliki parameter: startRowIndex, maximumRows.

Setelah membuat perubahan ini, sintaks deklaratif ObjectDataSource akan terlihat seperti berikut ini:

<asp:ObjectDataSource ID="ObjectDataSource1" runat="server"
    OldValuesParameterFormatString="original_{0}" TypeName="ProductsBLL"
    SelectMethod="GetProductsPaged" EnablePaging="True"
    SelectCountMethod="TotalNumberOfProducts">
</asp:ObjectDataSource>

Perhatikan bahwa EnablePaging properti dan SelectCountMethod telah diatur dan <asp:Parameter> elemen telah dihapus. Gambar 16 memperlihatkan cuplikan layar jendela Properti setelah perubahan ini dibuat.

Untuk Menggunakan Halaman Kustom, Konfigurasikan Kontrol ObjectDataSource

Gambar 16: Untuk Menggunakan Halaman Kustom, Konfigurasikan Kontrol ObjectDataSource

Setelah membuat perubahan ini, kunjungi halaman ini melalui browser. Anda akan melihat 10 produk terdaftar, dipesan menurut abjad. Luangkan waktu sejenak untuk menelusuri data satu halaman pada satu waktu. Meskipun tidak ada perbedaan visual dari perspektif pengguna akhir antara halaman default dan halaman kustom, halaman kustom lebih efisien melalui sejumlah besar data karena hanya mengambil rekaman yang perlu ditampilkan untuk halaman tertentu.

Data, Diurutkan berdasarkan Nama Produk, adalah Halaman Menggunakan Halaman Kustom

Gambar 17: Data, Diurutkan berdasarkan Nama Produk, adalah Halaman Menggunakan Halaman Kustom (Klik untuk melihat gambar ukuran penuh)

Catatan

Dengan halaman kustom, nilai jumlah halaman yang dikembalikan oleh ObjectDataSource SelectCountMethod disimpan dalam status tampilan GridView. Variabel PageIndexGridView lainnya , , EditIndexSelectedIndexDataKeys koleksi, dan sebagainya disimpan dalam status kontrol, yang dipertahankan terlepas dari nilai properti GridView.EnableViewState PageCount Karena nilai dipertahankan di seluruh postback menggunakan status tampilan, saat menggunakan antarmuka halaman yang menyertakan tautan untuk membawa Anda ke halaman terakhir, sangat penting bahwa status tampilan GridView diaktifkan. (Jika antarmuka halaman Anda tidak menyertakan tautan langsung ke halaman terakhir, maka Anda dapat menonaktifkan status tampilan.)

Mengklik tautan halaman terakhir menyebabkan postback dan menginstruksikan GridView untuk memperbarui propertinya PageIndex . Jika tautan halaman terakhir diklik, GridView menetapkan propertinya PageIndex ke nilai yang kurang dari propertinya PageCount . Dengan status tampilan dinonaktifkan, PageCount nilai hilang di seluruh postback dan PageIndex ditetapkan sebagai gantinya nilai bilangan bulat maksimum. Selanjutnya, GridView mencoba menentukan indeks baris awal dengan mengalikan PageSize properti dan PageCount . Ini menghasilkan karena produk melebihi ukuran bilangan bulat maksimum yang OverflowException diizinkan.

Menerapkan Penomoran dan Pengurutan Kustom

Implementasi halaman kustom kami saat ini mengharuskan urutan data di-paged melalui ditentukan secara statis saat membuat prosedur tersimpan GetProductsPaged . Namun, Anda mungkin telah mencatat bahwa tag pintar GridView berisi kotak centang Aktifkan Pengurutan selain opsi Aktifkan Penomoran Halaman. Sayangnya, menambahkan dukungan pengurutan ke GridView dengan implementasi penomoran halaman kustom kami saat ini hanya akan mengurutkan rekaman pada halaman data yang saat ini dilihat. Misalnya, jika Anda mengonfigurasi GridView untuk juga mendukung penomoran halaman dan kemudian, saat melihat halaman pertama data, mengurutkan menurut nama produk dalam urutan menurut, itu akan membalikkan urutan produk di halaman 1. Seperti yang ditunjukkan Gambar 18, seperti yang ditunjukkan Carnarvon Tigers sebagai produk pertama saat mengurutkan dalam urutan alfabet terbalik, yang mengabaikan 71 produk lain yang mengejar Carnarvon Tigers, menurut abjad; hanya rekaman tersebut pada halaman pertama yang dipertimbangkan dalam pengurutan.

Hanya Data yang Ditampilkan di Halaman Saat Ini yang Diurutkan

Gambar 18: Hanya Data yang Ditampilkan di Halaman Saat Ini yang Diurutkan (Klik untuk melihat gambar ukuran penuh)

Pengurutan hanya berlaku untuk halaman data saat ini karena pengurutan terjadi setelah data diambil dari metode BLL s GetProductsPaged , dan metode ini hanya mengembalikan rekaman tersebut untuk halaman tertentu. Untuk menerapkan pengurutan dengan benar, kita perlu meneruskan ekspresi pengurutan ke GetProductsPaged metode sehingga data dapat diberi peringkat dengan tepat sebelum mengembalikan halaman data tertentu. Kita akan melihat cara mencapai ini dalam tutorial berikutnya.

Menerapkan Halaman Kustom dan Menghapus

Jika Anda mengaktifkan fungsionalitas penghapusan di GridView yang datanya di-page menggunakan teknik penomoran halaman kustom, Anda akan menemukan bahwa saat menghapus rekaman terakhir dari halaman terakhir, GridView menghilang daripada dengan tepat mengurangi GridView.PageIndex Untuk mereprodusi bug ini, aktifkan penghapusan untuk tutorial yang baru saja kita buat. Buka halaman terakhir (halaman 9), di mana Anda akan melihat satu produk karena kami melakukan paging melalui 81 produk, 10 produk pada satu waktu. Hapus produk ini.

Setelah menghapus produk terakhir, GridView harus secara otomatis masuk ke halaman kedelapan, dan fungsionalitas tersebut dipamerkan dengan halaman default. Namun, dengan penomoran halaman kustom, setelah menghapus produk terakhir itu di halaman terakhir, GridView menghilang dari layar sama sekali. Alasan tepat mengapa ini terjadi sedikit di luar cakupan tutorial ini; lihat Menghapus Rekaman Terakhir di Halaman Terakhir dari GridView dengan Halaman Kustom untuk detail tingkat rendah tentang sumber masalah ini. Singkatnya karena urutan langkah-langkah berikut yang dilakukan oleh GridView saat tombol Hapus diklik:

  1. Menghapus rekaman
  2. Dapatkan rekaman yang sesuai untuk ditampilkan untuk yang ditentukan PageIndex dan PageSize
  3. Periksa untuk memastikan bahwa PageIndex tidak melebihi jumlah halaman data di sumber data; jika ya, secara otomatis mengurangi properti GridView s PageIndex
  4. Ikat halaman data yang sesuai ke GridView menggunakan rekaman yang diperoleh di Langkah 2

Masalah berasal dari fakta bahwa di Langkah 2 yang PageIndex digunakan saat mengambil rekaman yang akan ditampilkan masih PageIndex merupakan halaman terakhir yang catatan tunggalnya baru saja dihapus. Oleh karena itu, di Langkah 2, tidak ada rekaman yang dikembalikan karena halaman terakhir data tersebut tidak lagi berisi rekaman apa pun. Kemudian, di Langkah 3, GridView menyadari bahwa propertinya PageIndex lebih besar dari jumlah total halaman di sumber data (karena kami telah menghapus rekaman terakhir di halaman terakhir) dan karena itu mengurangi propertinya PageIndex . Di Langkah 4 GridView mencoba mengikat dirinya sendiri ke data yang diambil di Langkah 2; namun, di Langkah 2 tidak ada rekaman yang dikembalikan, oleh karena itu menghasilkan GridView kosong. Dengan halaman default, masalah ini tidak muncul karena di Langkah 2 semua rekaman diambil dari sumber data.

Untuk memperbaikinya, kami memiliki dua opsi. Yang pertama adalah membuat penanganan aktivitas untuk penanganan aktivitas GridView RowDeleted yang menentukan berapa banyak rekaman yang ditampilkan di halaman yang baru saja dihapus. Jika hanya ada satu rekaman, maka catatan yang baru saja dihapus pasti yang terakhir dan kita perlu mengurangi GridView s PageIndex. Tentu saja, kami hanya ingin memperbarui PageIndex jika operasi penghapusan benar-benar berhasil, yang dapat ditentukan dengan memastikan bahwa e.Exception properti adalah null.

Pendekatan ini berfungsi karena memperbarui PageIndex setelah Langkah 1 tetapi sebelum Langkah 2. Oleh karena itu, pada Langkah 2, kumpulan rekaman yang sesuai dikembalikan. Untuk mencapai hal ini, gunakan kode seperti berikut:

protected void GridView1_RowDeleted(object sender, GridViewDeletedEventArgs e)
{
    // If we just deleted the last row in the GridView, decrement the PageIndex
    if (e.Exception == null && GridView1.Rows.Count == 1)
        // we just deleted the last row
        GridView1.PageIndex = Math.Max(0, GridView1.PageIndex - 1);
}

Solusi alternatif adalah membuat penanganan aktivitas untuk peristiwa ObjectDataSource dan RowDeleted mengatur AffectedRows properti ke nilai 1. Setelah menghapus rekaman di Langkah 1 (tetapi sebelum mengambil kembali data di Langkah 2), GridView memperbarui propertinya PageIndex jika satu atau beberapa baris terpengaruh oleh operasi. Namun, AffectedRows properti tidak diatur oleh ObjectDataSource dan oleh karena itu langkah ini dihilangkan. Salah satu cara untuk menjalankan langkah ini adalah dengan mengatur AffectedRows properti secara manual jika operasi penghapusan berhasil diselesaikan. Ini dapat dicapai menggunakan kode seperti berikut:

protected void ObjectDataSource1_Deleted(
    object sender, ObjectDataSourceStatusEventArgs e)
{
    // If we get back a Boolean value from the DeleteProduct method and it's true,
    // then we successfully deleted the product. Set AffectedRows to 1
    if (e.ReturnValue is bool && ((bool)e.ReturnValue) == true)
        e.AffectedRows = 1;
}

Kode untuk kedua penanganan peristiwa ini dapat ditemukan di kelas code-behind contoh EfficientPaging.aspx .

Membandingkan Performa Halaman Default dan Kustom

Karena halaman kustom hanya mengambil rekaman yang diperlukan, sedangkan halaman default mengembalikan semua rekaman untuk setiap halaman yang ditampilkan, jelas bahwa penomor kustom lebih efisien daripada halaman default. Tetapi berapa banyak yang lebih efisien adalah penomor kustom? Perolehan performa seperti apa yang dapat dilihat dengan berpindah dari penomoran halaman default ke penomoran kustom?

Sayangnya, tidak ada satu ukuran yang sesuai dengan semua jawaban di sini. Perolehan performa tergantung pada sejumlah faktor, dua yang paling menonjol adalah jumlah rekaman yang di-paged through dan beban yang ditempatkan di server database dan saluran komunikasi antara server web dan server database. Untuk tabel kecil hanya dengan beberapa lusin rekaman, perbedaan performa mungkin dapat diabaikan. Untuk tabel besar, dengan ribuan hingga ratusan ribu baris, meskipun, perbedaan performanya akut.

Artikel saya, "Custom Paging in ASP.NET 2.0 with SQL Server 2005," berisi beberapa pengujian performa yang saya jalankan untuk menunjukkan perbedaan performa antara kedua teknik penomoran ini saat penomor melalui tabel database dengan 50.000 rekaman. Dalam pengujian ini saya memeriksa waktu untuk menjalankan kueri di tingkat SQL Server (menggunakan SQL Profiler) dan di halaman ASP.NET menggunakan fitur pelacakan ASP.NET. Perlu diingat bahwa pengujian ini dijalankan pada kotak pengembangan saya dengan satu pengguna aktif, dan oleh karena itu tidak ilmiah dan tidak menipu pola beban situs web biasa. Terlepas dari itu, hasilnya menggambarkan perbedaan relatif dalam waktu eksekusi untuk halaman default dan kustom saat bekerja dengan data dalam jumlah yang cukup besar.

Rata-rata Durasi (dtk) Membaca
Default Paging SQL Profiler 1.411 383
Paging Kustom SQL Profiler 0,002 29
Pelacakan ASP.NET Halaman Default 2.379 N/A
Jejak ASP.NET Halaman Kustom 0.029 N/A

Seperti yang Anda lihat, mengambil halaman data tertentu rata-rata memerlukan 354 bacaan lebih sedikit dan diselesaikan dalam waktu yang singkat. Pada halaman ASP.NET, halaman kustom dapat dirender mendekati 1/100th dari waktu yang diperlukan saat menggunakan halaman default.

Ringkasan

Halaman default adalah cinch untuk mengimplementasikan hanya centang pada kotak centang Aktifkan Halaman di tag pintar kontrol Web data tetapi kesederhanaan tersebut dikenakan biaya performa. Dengan halaman default, ketika pengguna meminta halaman data apa pun, semua rekaman dikembalikan, meskipun hanya sebagian kecil dari mereka yang dapat ditampilkan. Untuk memerangi overhead performa ini, ObjectDataSource menawarkan penahapan kustom opsi halaman alternatif.

Meskipun penomor kustom meningkat pada masalah performa halaman default dengan hanya mengambil rekaman yang perlu ditampilkan, lebih terlibat untuk menerapkan penomor kustom. Pertama, kueri harus ditulis yang dengan benar (dan efisien) mengakses subset rekaman tertentu yang diminta. Ini dapat dicapai dengan sejumlah cara; yang kami periksa dalam tutorial ini adalah menggunakan fungsi baru ROW_NUMBER() SQL Server 2005 untuk memberi peringkat hasil, dan kemudian mengembalikan hanya hasil yang peringkatnya termasuk dalam rentang tertentu. Selain itu, kita perlu menambahkan sarana untuk menentukan jumlah total rekaman yang di-paged through. Setelah membuat metode DAL dan BLL ini, kita juga perlu mengonfigurasi ObjectDataSource sehingga dapat menentukan berapa banyak total rekaman yang di-paged through dan dapat meneruskan nilai Indeks Baris Mulai dan Baris Maksimum dengan benar ke BLL.

Saat menerapkan penomoran kustom memang memerlukan sejumlah langkah dan tidak hampir sesingkat penomoran default, penomoran halaman kustom adalah kebutuhan ketika penomoran melalui data dalam jumlah yang cukup besar. Seperti yang ditunjukkan oleh hasil pemeriksaan, halaman kustom dapat menumpahkan detik dari waktu render halaman ASP.NET dan dapat meringankan beban di server database dengan satu ore lebih banyak pesanan besarnya.

Selamat Pemrograman!

Tentang Penulis

Scott Mitchell, penulis tujuh buku ASP/ASP.NET dan pendiri 4GuysFromRolla.com, telah bekerja sama dengan teknologi Microsoft Web sejak 1998. Scott bekerja sebagai konsultan, pelatih, dan penulis independen. Buku terbarunya adalah Sams Teach Yourself ASP.NET 2.0 dalam 24 Jam. Dia dapat dijangkau di mitchell@4GuysFromRolla.com.