Tutorial: Menambahkan pengurutan, pemfilteran, dan penomoran - ASP.NET MVC dengan EF Core
Dalam tutorial sebelumnya, Anda menerapkan sekumpulan halaman web untuk operasi CRUD dasar untuk entitas Siswa. Dalam tutorial ini Anda akan menambahkan fungsi pengurutan, pemfilteran, dan penomoran halaman ke halaman Indeks Siswa. Anda juga akan membuat halaman yang melakukan pengelompokan sederhana.
Ilustrasi berikut menunjukkan seperti apa tampilan halaman saat Anda selesai. Judul kolom adalah tautan yang bisa diklik pengguna untuk mengurutkan menurut kolom tersebut. Mengklik judul kolom berulang kali beralih antara urutan urutan naik dan turun.
Di tutorial ini, Anda akan:
- Menambahkan tautan pengurutan kolom
- Tambahkan kotak Pencarian
- Menambahkan halaman ke Indeks Siswa
- Menambahkan halaman ke metode Indeks
- Menambahkan tautan halaman
- Membuat halaman Tentang
Prasyarat
Menambahkan tautan pengurutan kolom
Untuk menambahkan pengurutan ke halaman Indeks Siswa, Anda akan mengubah Index
metode pengontrol Siswa dan menambahkan kode ke tampilan Indeks Siswa.
Menambahkan Fungsionalitas pengurutan ke metode Indeks
Di StudentsController.cs
, ganti Index
metode dengan kode berikut:
public async Task<IActionResult> Index(string sortOrder)
{
ViewData["NameSortParm"] = String.IsNullOrEmpty(sortOrder) ? "name_desc" : "";
ViewData["DateSortParm"] = sortOrder == "Date" ? "date_desc" : "Date";
var students = from s in _context.Students
select s;
switch (sortOrder)
{
case "name_desc":
students = students.OrderByDescending(s => s.LastName);
break;
case "Date":
students = students.OrderBy(s => s.EnrollmentDate);
break;
case "date_desc":
students = students.OrderByDescending(s => s.EnrollmentDate);
break;
default:
students = students.OrderBy(s => s.LastName);
break;
}
return View(await students.AsNoTracking().ToListAsync());
}
Kode ini menerima sortOrder
parameter dari string kueri di URL. Nilai string kueri disediakan oleh ASP.NET Core MVC sebagai parameter untuk metode tindakan. Parameter akan menjadi string yang merupakan "Nama" atau "Tanggal", secara opsional diikuti oleh garis bawah dan string "desc" untuk menentukan urutan menurut. Urutan sortir default adalah menaik.
Pertama kali halaman Indeks diminta, tidak ada string kueri. Siswa ditampilkan dalam urutan naik berdasarkan nama belakang, yang merupakan default seperti yang ditetapkan oleh kasus fall-through dalam switch
pernyataan. Saat pengguna mengklik hyperlink judul kolom, nilai yang sesuai sortOrder
disediakan dalam string kueri.
Dua ViewData
elemen (NameSortParm dan DateSortParm) digunakan oleh tampilan untuk mengonfigurasi hyperlink judul kolom dengan nilai string kueri yang sesuai.
public async Task<IActionResult> Index(string sortOrder)
{
ViewData["NameSortParm"] = String.IsNullOrEmpty(sortOrder) ? "name_desc" : "";
ViewData["DateSortParm"] = sortOrder == "Date" ? "date_desc" : "Date";
var students = from s in _context.Students
select s;
switch (sortOrder)
{
case "name_desc":
students = students.OrderByDescending(s => s.LastName);
break;
case "Date":
students = students.OrderBy(s => s.EnrollmentDate);
break;
case "date_desc":
students = students.OrderByDescending(s => s.EnrollmentDate);
break;
default:
students = students.OrderBy(s => s.LastName);
break;
}
return View(await students.AsNoTracking().ToListAsync());
}
Ini adalah pernyataan terner. Yang pertama menentukan bahwa jika sortOrder
parameter null atau kosong, NameSortParm harus diatur ke "name_desc"; jika tidak, parameter harus diatur ke string kosong. Kedua pernyataan ini memungkinkan tampilan untuk mengatur hyperlink judul kolom sebagai berikut:
Urutan pengurutan saat ini | Hyperlink Nama Belakang | Hyperlink Tanggal |
---|---|---|
Nama Belakang naik | Urut turun | urutan naik |
Nama Belakang turun | urutan naik | urutan naik |
Tanggal naik | urutan naik | Urut turun |
Tanggal turun | urutan naik | urutan naik |
Metode ini menggunakan LINQ ke Entitas untuk menentukan kolom yang akan diurutkan. Kode membuat IQueryable
variabel sebelum pernyataan pengalihan, memodifikasinya dalam pernyataan pengalihan, dan memanggil ToListAsync
metode setelah switch
pernyataan. Saat Anda membuat dan mengubah IQueryable
variabel, tidak ada kueri yang dikirim ke database. Kueri tidak dijalankan sampai Anda mengonversi IQueryable
objek menjadi koleksi dengan memanggil metode seperti ToListAsync
. Oleh karena itu, kode ini menghasilkan satu kueri yang tidak dijalankan sampai return View
pernyataan.
Kode ini bisa mendapatkan verbose dengan sejumlah besar kolom. Tutorial terakhir dalam seri ini menunjukkan cara menulis kode yang memungkinkan Anda meneruskan nama OrderBy
kolom dalam variabel string.
Menambahkan hyperlink judul kolom ke tampilan Indeks Siswa
Ganti kode di Views/Students/Index.cshtml
, dengan kode berikut untuk menambahkan hyperlink judul kolom. Baris yang diubah disorot.
@model IEnumerable<ContosoUniversity.Models.Student>
@{
ViewData["Title"] = "Index";
}
<h2>Index</h2>
<p>
<a asp-action="Create">Create New</a>
</p>
<table class="table">
<thead>
<tr>
<th>
<a asp-action="Index" asp-route-sortOrder="@ViewData["NameSortParm"]">@Html.DisplayNameFor(model => model.LastName)</a>
</th>
<th>
@Html.DisplayNameFor(model => model.FirstMidName)
</th>
<th>
<a asp-action="Index" asp-route-sortOrder="@ViewData["DateSortParm"]">@Html.DisplayNameFor(model => model.EnrollmentDate)</a>
</th>
<th></th>
</tr>
</thead>
<tbody>
@foreach (var item in Model) {
<tr>
<td>
@Html.DisplayFor(modelItem => item.LastName)
</td>
<td>
@Html.DisplayFor(modelItem => item.FirstMidName)
</td>
<td>
@Html.DisplayFor(modelItem => item.EnrollmentDate)
</td>
<td>
<a asp-action="Edit" asp-route-id="@item.ID">Edit</a> |
<a asp-action="Details" asp-route-id="@item.ID">Details</a> |
<a asp-action="Delete" asp-route-id="@item.ID">Delete</a>
</td>
</tr>
}
</tbody>
</table>
Kode ini menggunakan informasi dalam ViewData
properti untuk menyiapkan hyperlink dengan nilai string kueri yang sesuai.
Jalankan aplikasi, pilih tab Siswa , dan klik judul kolom Nama Belakang dan Tanggal Pendaftaran untuk memverifikasi bahwa pengurutan berfungsi.
Tambahkan kotak Pencarian
Untuk menambahkan pemfilteran ke halaman Indeks Siswa, Anda akan menambahkan kotak teks dan tombol kirim ke tampilan dan membuat perubahan terkait dalam Index
metode . Kotak teks akan memungkinkan Anda memasukkan string untuk dicari di bidang nama depan dan nama belakang.
Menambahkan fungsionalitas pemfilteran ke metode Indeks
Di StudentsController.cs
, ganti Index
metode dengan kode berikut (perubahan disorot).
public async Task<IActionResult> Index(string sortOrder, string searchString)
{
ViewData["NameSortParm"] = String.IsNullOrEmpty(sortOrder) ? "name_desc" : "";
ViewData["DateSortParm"] = sortOrder == "Date" ? "date_desc" : "Date";
ViewData["CurrentFilter"] = searchString;
var students = from s in _context.Students
select s;
if (!String.IsNullOrEmpty(searchString))
{
students = students.Where(s => s.LastName.Contains(searchString)
|| s.FirstMidName.Contains(searchString));
}
switch (sortOrder)
{
case "name_desc":
students = students.OrderByDescending(s => s.LastName);
break;
case "Date":
students = students.OrderBy(s => s.EnrollmentDate);
break;
case "date_desc":
students = students.OrderByDescending(s => s.EnrollmentDate);
break;
default:
students = students.OrderBy(s => s.LastName);
break;
}
return View(await students.AsNoTracking().ToListAsync());
}
Anda telah menambahkan searchString
parameter ke Index
metode . Nilai string pencarian diterima dari kotak teks yang akan Anda tambahkan ke tampilan Indeks. Anda juga telah menambahkan ke pernyataan LINQ di mana klausa yang hanya memilih siswa yang nama depan atau nama belakangnya berisi string pencarian. Pernyataan yang menambahkan klausul di mana dijalankan hanya jika ada nilai untuk dicari.
Catatan
Di sini Anda memanggil Where
metode pada IQueryable
objek, dan filter akan diproses di server. Dalam beberapa skenario, Anda mungkin memanggil Where
metode sebagai metode ekstensi pada koleksi dalam memori. (Misalnya, Anda mengubah referensi menjadi _context.Students
sehingga alih-alih EF DbSet
mereferensikan metode repositori yang mengembalikan IEnumerable
koleksi.) Hasilnya biasanya akan sama tetapi dalam beberapa kasus mungkin berbeda.
Misalnya, implementasi .NET Framework dari Contains
metode melakukan perbandingan peka huruf besar/kecil secara default, tetapi di SQL Server ini ditentukan oleh pengaturan kolase instans SQL Server. Pengaturan tersebut default ke tidak peka huruf besar/kecil. Anda dapat memanggil ToUpper
metode untuk membuat pengujian secara eksplisit tidak peka huruf besar/kecil: Where(s => s.LastName.ToUpper(). Contains(searchString.ToUpper()). Itu akan memastikan bahwa hasilnya tetap sama jika Anda mengubah kode nanti untuk menggunakan repositori yang mengembalikan IEnumerable
koleksi alih-alih IQueryable
objek. (Ketika Anda memanggil Contains
metode pada IEnumerable
koleksi, Anda mendapatkan implementasi .NET Framework; ketika Anda memanggilnya pada IQueryable
objek, Anda mendapatkan implementasi penyedia database.) Namun, ada penalti performa untuk solusi ini. Kode ToUpper
akan menempatkan fungsi dalam klausul WHERE dari pernyataan TSQL SELECT. Itu akan mencegah pengoptimal menggunakan indeks. Mengingat bahwa SQL sebagian besar diinstal sebagai tidak peka huruf besar/kecil, yang terbaik adalah menghindari ToUpper
kode sampai Anda bermigrasi ke penyimpanan data peka huruf besar/kecil.
Menambahkan Kotak Pencarian ke Tampilan Indeks Siswa
Di Views/Student/Index.cshtml
, tambahkan kode yang disorot segera sebelum tag tabel pembuka untuk membuat keterangan, kotak teks, dan tombol Cari .
<p>
<a asp-action="Create">Create New</a>
</p>
<form asp-action="Index" method="get">
<div class="form-actions no-color">
<p>
Find by name: <input type="text" name="SearchString" value="@ViewData["CurrentFilter"]" />
<input type="submit" value="Search" class="btn btn-default" /> |
<a asp-action="Index">Back to Full List</a>
</p>
</div>
</form>
<table class="table">
Kode ini menggunakan pembantu <form>
tag untuk menambahkan kotak teks pencarian dan tombol. Secara default, pembantu <form>
tag mengirimkan data formulir dengan POST, yang berarti bahwa parameter diteruskan dalam isi pesan HTTP dan bukan di URL sebagai string kueri. Saat Anda menentukan HTTP GET, data formulir diteruskan dalam URL sebagai string kueri, yang memungkinkan pengguna untuk menandai URL. Panduan W3C menyarankan agar Anda menggunakan GET saat tindakan tidak menghasilkan pembaruan.
Jalankan aplikasi, pilih tab Siswa , masukkan string pencarian, dan klik Cari untuk memverifikasi bahwa pemfilteran berfungsi.
Perhatikan bahwa URL berisi string pencarian.
http://localhost:5813/Students?SearchString=an
Jika Anda menandai halaman ini, Anda akan mendapatkan daftar yang difilter saat menggunakan marka buku. method="get"
Menambahkan ke form
tag adalah apa yang menyebabkan string kueri dihasilkan.
Pada tahap ini, jika Anda mengklik tautan pengurutan judul kolom, Anda akan kehilangan nilai filter yang Anda masukkan di kotak Pencarian . Anda akan memperbaikinya di bagian berikutnya.
Menambahkan halaman ke Indeks Siswa
Untuk menambahkan halaman halaman Indeks Siswa, Anda akan membuat PaginatedList
kelas yang menggunakan Skip
pernyataan dan Take
untuk memfilter data di server alih-alih selalu mengambil semua baris tabel. Kemudian Anda akan membuat perubahan tambahan dalam Index
metode dan menambahkan tombol halaman ke Index
tampilan. Ilustrasi berikut menunjukkan tombol halaman.
Di folder proyek, buat PaginatedList.cs
, lalu ganti kode templat dengan kode berikut.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore;
namespace ContosoUniversity
{
public class PaginatedList<T> : List<T>
{
public int PageIndex { get; private set; }
public int TotalPages { get; private set; }
public PaginatedList(List<T> items, int count, int pageIndex, int pageSize)
{
PageIndex = pageIndex;
TotalPages = (int)Math.Ceiling(count / (double)pageSize);
this.AddRange(items);
}
public bool HasPreviousPage => PageIndex > 1;
public bool HasNextPage => PageIndex < TotalPages;
public static async Task<PaginatedList<T>> CreateAsync(IQueryable<T> source, int pageIndex, int pageSize)
{
var count = await source.CountAsync();
var items = await source.Skip((pageIndex - 1) * pageSize).Take(pageSize).ToListAsync();
return new PaginatedList<T>(items, count, pageIndex, pageSize);
}
}
}
Metode CreateAsync
dalam kode ini mengambil ukuran halaman dan nomor halaman dan menerapkan pernyataan dan Take
yang sesuai Skip
ke IQueryable
. Ketika ToListAsync
dipanggil pada IQueryable
, itu akan mengembalikan Daftar yang hanya berisi halaman yang diminta. Properti HasPreviousPage
dan HasNextPage
dapat digunakan untuk mengaktifkan atau menonaktifkan tombol halaman Sebelumnya dan Berikutnya .
Metode CreateAsync
digunakan alih-alih konstruktor untuk membuat PaginatedList<T>
objek karena konstruktor tidak dapat menjalankan kode asinkron.
Menambahkan halaman ke metode Indeks
Di StudentsController.cs
, ganti Index
metode dengan kode berikut.
public async Task<IActionResult> Index(
string sortOrder,
string currentFilter,
string searchString,
int? pageNumber)
{
ViewData["CurrentSort"] = sortOrder;
ViewData["NameSortParm"] = String.IsNullOrEmpty(sortOrder) ? "name_desc" : "";
ViewData["DateSortParm"] = sortOrder == "Date" ? "date_desc" : "Date";
if (searchString != null)
{
pageNumber = 1;
}
else
{
searchString = currentFilter;
}
ViewData["CurrentFilter"] = searchString;
var students = from s in _context.Students
select s;
if (!String.IsNullOrEmpty(searchString))
{
students = students.Where(s => s.LastName.Contains(searchString)
|| s.FirstMidName.Contains(searchString));
}
switch (sortOrder)
{
case "name_desc":
students = students.OrderByDescending(s => s.LastName);
break;
case "Date":
students = students.OrderBy(s => s.EnrollmentDate);
break;
case "date_desc":
students = students.OrderByDescending(s => s.EnrollmentDate);
break;
default:
students = students.OrderBy(s => s.LastName);
break;
}
int pageSize = 3;
return View(await PaginatedList<Student>.CreateAsync(students.AsNoTracking(), pageNumber ?? 1, pageSize));
}
Kode ini menambahkan parameter nomor halaman, parameter urutan pengurutan saat ini, dan parameter filter saat ini ke tanda tangan metode.
public async Task<IActionResult> Index(
string sortOrder,
string currentFilter,
string searchString,
int? pageNumber)
Pertama kali halaman ditampilkan, atau jika pengguna belum mengklik tautan penomoran halaman atau pengurutan, semua parameter akan null. Jika tautan halaman diklik, variabel halaman akan berisi nomor halaman yang akan ditampilkan.
Elemen ViewData
bernama CurrentSort menyediakan tampilan dengan urutan pengurutan saat ini, karena ini harus disertakan dalam tautan halaman agar urutan pengurutan tetap sama saat penomoran halaman.
ViewData
Elemen bernama CurrentFilter menyediakan tampilan dengan string filter saat ini. Nilai ini harus disertakan dalam tautan halaman untuk mempertahankan pengaturan filter selama halaman, dan harus dipulihkan ke kotak teks saat halaman diputar ulang.
Jika string pencarian diubah selama halaman, halaman harus direset ke 1, karena filter baru dapat menghasilkan data yang berbeda untuk ditampilkan. String pencarian diubah saat nilai dimasukkan dalam kotak teks dan tombol Kirim ditekan. Dalam hal ini, searchString
parameter tidak null.
if (searchString != null)
{
pageNumber = 1;
}
else
{
searchString = currentFilter;
}
Di akhir Index
metode, metode mengonversi PaginatedList.CreateAsync
kueri siswa menjadi satu halaman siswa dalam jenis koleksi yang mendukung penomor. Halaman tunggal siswa tersebut kemudian diteruskan ke tampilan.
return View(await PaginatedList<Student>.CreateAsync(students.AsNoTracking(), pageNumber ?? 1, pageSize));
Metode ini PaginatedList.CreateAsync
mengambil nomor halaman. Dua tanda tanya mewakili operator null-coalescing. Operator null-coalescing mendefinisikan nilai default untuk jenis nullable; ekspresi (pageNumber ?? 1)
berarti mengembalikan nilai pageNumber
jika memiliki nilai, atau mengembalikan 1 jika pageNumber
null.
Menambahkan tautan halaman
Di Views/Students/Index.cshtml
, ganti kode yang ada dengan kode berikut. Perubahan disorot.
@model PaginatedList<ContosoUniversity.Models.Student>
@{
ViewData["Title"] = "Index";
}
<h2>Index</h2>
<p>
<a asp-action="Create">Create New</a>
</p>
<form asp-action="Index" method="get">
<div class="form-actions no-color">
<p>
Find by name: <input type="text" name="SearchString" value="@ViewData["CurrentFilter"]" />
<input type="submit" value="Search" class="btn btn-default" /> |
<a asp-action="Index">Back to Full List</a>
</p>
</div>
</form>
<table class="table">
<thead>
<tr>
<th>
<a asp-action="Index" asp-route-sortOrder="@ViewData["NameSortParm"]" asp-route-currentFilter="@ViewData["CurrentFilter"]">Last Name</a>
</th>
<th>
First Name
</th>
<th>
<a asp-action="Index" asp-route-sortOrder="@ViewData["DateSortParm"]" asp-route-currentFilter="@ViewData["CurrentFilter"]">Enrollment Date</a>
</th>
<th></th>
</tr>
</thead>
<tbody>
@foreach (var item in Model)
{
<tr>
<td>
@Html.DisplayFor(modelItem => item.LastName)
</td>
<td>
@Html.DisplayFor(modelItem => item.FirstMidName)
</td>
<td>
@Html.DisplayFor(modelItem => item.EnrollmentDate)
</td>
<td>
<a asp-action="Edit" asp-route-id="@item.ID">Edit</a> |
<a asp-action="Details" asp-route-id="@item.ID">Details</a> |
<a asp-action="Delete" asp-route-id="@item.ID">Delete</a>
</td>
</tr>
}
</tbody>
</table>
@{
var prevDisabled = !Model.HasPreviousPage ? "disabled" : "";
var nextDisabled = !Model.HasNextPage ? "disabled" : "";
}
<a asp-action="Index"
asp-route-sortOrder="@ViewData["CurrentSort"]"
asp-route-pageNumber="@(Model.PageIndex - 1)"
asp-route-currentFilter="@ViewData["CurrentFilter"]"
class="btn btn-default @prevDisabled">
Previous
</a>
<a asp-action="Index"
asp-route-sortOrder="@ViewData["CurrentSort"]"
asp-route-pageNumber="@(Model.PageIndex + 1)"
asp-route-currentFilter="@ViewData["CurrentFilter"]"
class="btn btn-default @nextDisabled">
Next
</a>
Pernyataan @model
di bagian atas halaman menentukan bahwa tampilan sekarang mendapatkan PaginatedList<T>
objek alih-alih List<T>
objek.
Tautan header kolom menggunakan string kueri untuk meneruskan string pencarian saat ini ke pengontrol sehingga pengguna dapat mengurutkan dalam hasil filter:
<a asp-action="Index" asp-route-sortOrder="@ViewData["DateSortParm"]" asp-route-currentFilter ="@ViewData["CurrentFilter"]">Enrollment Date</a>
Tombol halaman ditampilkan oleh pembantu tag:
<a asp-action="Index"
asp-route-sortOrder="@ViewData["CurrentSort"]"
asp-route-pageNumber="@(Model.PageIndex - 1)"
asp-route-currentFilter="@ViewData["CurrentFilter"]"
class="btn btn-default @prevDisabled">
Previous
</a>
Jalankan aplikasi dan buka halaman Siswa.
Klik tautan halaman dalam urutan pengurutan yang berbeda untuk memastikan penomoran halaman berfungsi. Kemudian masukkan string pencarian dan coba halaman lagi untuk memverifikasi bahwa penomoran halaman juga berfungsi dengan benar dengan pengurutan dan pemfilteran.
Membuat halaman Tentang
Untuk halaman Tentang situs web Contoso University, Anda akan menampilkan berapa banyak siswa yang telah mendaftar untuk setiap tanggal pendaftaran. Ini memerlukan pengelompokan dan perhitungan sederhana pada grup. Untuk mencapai hal ini, Anda akan melakukan hal berikut:
- Buat kelas model tampilan untuk data yang perlu Anda teruskan ke tampilan.
- Buat metode Tentang di Home pengontrol.
- Buat tampilan Tentang.
Membuat model tampilan
Buat folder SchoolViewModels di folder Model .
Di folder baru, tambahkan file EnrollmentDateGroup.cs
kelas dan ganti kode templat dengan kode berikut:
using System;
using System.ComponentModel.DataAnnotations;
namespace ContosoUniversity.Models.SchoolViewModels
{
public class EnrollmentDateGroup
{
[DataType(DataType.Date)]
public DateTime? EnrollmentDate { get; set; }
public int StudentCount { get; set; }
}
}
Home Mengubah Pengontrol
Di HomeController.cs
, tambahkan pernyataan penggunaan berikut di bagian atas file:
using Microsoft.EntityFrameworkCore;
using ContosoUniversity.Data;
using ContosoUniversity.Models.SchoolViewModels;
using Microsoft.Extensions.Logging;
Tambahkan variabel kelas untuk konteks database segera setelah kurung kurawal pembuka untuk kelas , dan dapatkan instans konteks dari ASP.NET Core DI:
public class HomeController : Controller
{
private readonly ILogger<HomeController> _logger;
private readonly SchoolContext _context;
public HomeController(ILogger<HomeController> logger, SchoolContext context)
{
_logger = logger;
_context = context;
}
About
Tambahkan metode dengan kode berikut:
public async Task<ActionResult> About()
{
IQueryable<EnrollmentDateGroup> data =
from student in _context.Students
group student by student.EnrollmentDate into dateGroup
select new EnrollmentDateGroup()
{
EnrollmentDate = dateGroup.Key,
StudentCount = dateGroup.Count()
};
return View(await data.AsNoTracking().ToListAsync());
}
Pernyataan LINQ mengelompokkan entitas siswa berdasarkan tanggal pendaftaran, menghitung jumlah entitas di setiap grup, dan menyimpan hasilnya dalam kumpulan EnrollmentDateGroup
objek model tampilan.
Membuat Tampilan Tentang
Views/Home/About.cshtml
Tambahkan file dengan kode berikut:
@model IEnumerable<ContosoUniversity.Models.SchoolViewModels.EnrollmentDateGroup>
@{
ViewData["Title"] = "Student Body Statistics";
}
<h2>Student Body Statistics</h2>
<table>
<tr>
<th>
Enrollment Date
</th>
<th>
Students
</th>
</tr>
@foreach (var item in Model)
{
<tr>
<td>
@Html.DisplayFor(modelItem => item.EnrollmentDate)
</td>
<td>
@item.StudentCount
</td>
</tr>
}
</table>
Jalankan aplikasi dan buka halaman Tentang. Jumlah siswa untuk setiap tanggal pendaftaran ditampilkan dalam tabel.
Mendapatkan kode
Unduh atau lihat aplikasi yang telah selesai.
Langkah berikutnya
Di tutorial ini, Anda akan:
- Menambahkan tautan pengurutan kolom
- Menambahkan kotak Pencarian
- Menambahkan halaman ke Indeks Siswa
- Menambahkan halaman ke metode Indeks
- Menambahkan tautan halaman
- Membuat halaman Tentang
Lanjutkan ke tutorial berikutnya untuk mempelajari cara menangani perubahan model data dengan menggunakan migrasi.
ASP.NET Core
Saran dan Komentar
https://aka.ms/ContentUserFeedback.
Segera hadir: Sepanjang tahun 2024 kami akan menghentikan penggunaan GitHub Issues sebagai mekanisme umpan balik untuk konten dan menggantinya dengan sistem umpan balik baru. Untuk mengetahui informasi selengkapnya, lihat:Kirim dan lihat umpan balik untuk