Bagikan melalui


Penentuan halaman

Penomoran halaman mengacu pada pengambilan hasil di halaman, bukan sekaligus; ini biasanya dilakukan untuk hasil yang besar, di mana antarmuka pengguna ditampilkan yang memungkinkan pengguna untuk menavigasi ke halaman hasil berikutnya atau sebelumnya.

Peringatan

Terlepas dari metode penomoran halaman yang digunakan, selalu pastikan bahwa pemesanan Anda sepenuhnya unik. Misalnya, jika hasil diurutkan hanya berdasarkan tanggal, tetapi mungkin ada beberapa hasil dengan tanggal yang sama, maka hasilnya dapat dilewati saat paginating karena diurutkan secara berbeda di dua kueri paginating. Pemesanan berdasarkan tanggal dan ID (atau properti unik atau kombinasi properti lainnya) membuat pemesanan sepenuhnya unik dan menghindari masalah ini. Perhatikan bahwa database relasional tidak menerapkan pengurutan apa pun secara default, bahkan pada kunci utama.

Catatan

Azure Cosmos DB memiliki mekanisme sendiri untuk penomoran halaman, lihat halaman dokumentasi khusus.

Penomoran halaman offset

Cara umum untuk menerapkan penomoran halaman dengan database adalah dengan menggunakan Skip operator LINQ dan Take (OFFSET dan LIMIT di SQL). Mengingat ukuran halaman 10 hasil, halaman ketiga dapat diambil dengan EF Core sebagai berikut:

var position = 20;
var nextPage = context.Posts
    .OrderBy(b => b.PostId)
    .Skip(position)
    .Take(10)
    .ToList();

Sayangnya, meskipun teknik ini sangat intuitif, teknik ini juga memiliki beberapa kekurangan yang parah:

  1. Database masih harus memproses 20 entri pertama, meskipun tidak dikembalikan ke aplikasi; ini menciptakan beban komputasi yang mungkin signifikan yang meningkat dengan jumlah baris yang dilewati.
  2. Jika ada pembaruan yang terjadi secara bersamaan, penomoran halaman Anda mungkin akhirnya melewati entri tertentu atau menunjukkannya dua kali. Misalnya, jika entri dihapus saat pengguna berpindah dari halaman 2 ke 3, seluruh hasil "bergeser ke atas", dan satu entri akan dilewati.

Penomoran kunci

Alternatif yang direkomendasikan untuk paginasi berbasis offset - kadang-kadang disebut keyset pagination atau penomoran berbasis pencarian - adalah dengan hanya menggunakan WHERE klausul untuk melewati baris, bukan offset. Ini berarti ingat nilai yang relevan dari entri terakhir yang diambil (alih-alih offsetnya), dan untuk meminta baris berikutnya setelah baris tersebut. Misalnya, dengan asumsi entri terakhir di halaman terakhir yang kami ambil memiliki nilai ID 55, kami hanya akan melakukan hal berikut:

var lastId = 55;
var nextPage = context.Posts
    .OrderBy(b => b.PostId)
    .Where(b => b.PostId > lastId)
    .Take(10)
    .ToList();

Dengan asumsi indeks didefinisikan pada PostId, kueri ini sangat efisien, dan juga tidak sensitif terhadap perubahan bersamaan yang terjadi dalam nilai Id yang lebih rendah.

Keyset pagination sesuai untuk antarmuka penomoran halaman di mana pengguna menavigasi maju dan mundur, tetapi tidak mendukung akses acak, di mana pengguna dapat melompat ke halaman tertentu. Paginasi akses acak memerlukan penggunaan paginasi offset seperti yang dijelaskan di atas; karena kekurangan paginasi offset, pertimbangkan dengan cermat apakah paginasi akses acak benar-benar diperlukan untuk kasus penggunaan Anda, atau jika navigasi halaman berikutnya/sebelumnya sudah cukup. Jika penomoran halaman akses acak diperlukan, implementasi yang kuat dapat menggunakan penomoran halaman keyset saat navigasi ke halaman berikutnya/sebelumnya, dan navigasi offset saat melompat ke halaman lain.

Beberapa kunci penomoran halaman

Saat menggunakan keyset pagination, sering kali perlu untuk memesan lebih dari satu properti. Misalnya, kueri berikut paginasi menurut tanggal dan ID:

var lastDate = new DateTime(2020, 1, 1);
var lastId = 55;
var nextPage = context.Posts
    .OrderBy(b => b.Date)
    .ThenBy(b => b.PostId)
    .Where(b => b.Date > lastDate || (b.Date == lastDate && b.PostId > lastId))
    .Take(10)
    .ToList();

Ini memastikan bahwa halaman berikutnya memilih persis di mana halaman sebelumnya berakhir. Karena lebih banyak kunci pengurutan ditambahkan, klausul tambahan dapat ditambahkan.

Catatan

Sebagian besar database SQL mendukung versi di atas yang lebih sederhana dan lebih efisien, menggunakan nilai baris: WHERE (Date, Id) > (@lastDate, @lastId). EF Core saat ini tidak mendukung mengekspresikan ini dalam kueri LINQ, ini dilacak oleh #26822.

Indeks

Seperti halnya kueri lain, pengindeksan yang tepat sangat penting untuk performa yang baik: pastikan untuk memiliki indeks yang sesuai dengan urutan penomoran halaman Anda. Jika mengurutkan menurut lebih dari satu kolom, indeks di atas beberapa kolom tersebut dapat ditentukan; ini disebut indeks komposit.

Untuk informasi selengkapnya, lihat halaman dokumentasi tentang indeks.

Sumber Daya Tambahan:

  • Untuk mempelajari lebih lanjut tentang kekurangan paginasi berbasis offset dan tentang penomoran keyset, lihat posting ini.
  • Sesi Standup Komunitas Data .NET di mana kita membahas pagination dan demo semua konsep di atas.
  • Presentasi mendalam teknis membandingkan offset dan keyset pagination. Meskipun konten berkaitan dengan database PostgreSQL, informasi umum juga berlaku untuk database relasional lainnya.
  • Untuk ekstensi di atas EF Core yang menyederhanakan paginasi keyset, lihat MR. EntityFrameworkCore.KeysetPagination dan MR. AspNetCore.Pagination.