Samouczek: dodawanie sortowania, filtrowania i stronicowania za pomocą platformy Entity Framework w aplikacji MVC ASP.NET
W poprzednim samouczku zaimplementowano zestaw stron internetowych dla podstawowych operacji CRUD dla Student
jednostek. W tym samouczku dodasz funkcje sortowania, filtrowania i stronicowania do strony Indeks uczniów . Utworzysz również prostą stronę grupowania.
Na poniższej ilustracji przedstawiono wygląd strony po zakończeniu pracy. Nagłówki kolumn to linki, które użytkownik może kliknąć, aby posortować według tej kolumny. Kliknięcie nagłówka kolumny wielokrotnie przełącza się między rosnącą i malejącą kolejnością sortowania.
W tym samouczku zostały wykonane następujące czynności:
- Dodawanie łączy sortowania kolumn
- Dodawanie pola wyszukiwania
- Dodawanie stronicowania
- Tworzenie strony Informacje
Wymagania wstępne
Dodawanie łączy sortowania kolumn
Aby dodać sortowanie do strony Indeks uczniówStudent
, zmienisz Index
metodę kontrolera i dodasz kod do Student
widoku Indeks.
Dodawanie funkcji sortowania do metody Index
W pliku Controllers\StudentController.cs zastąp metodę
Index
następującym kodem:public ActionResult Index(string sortOrder) { ViewBag.NameSortParm = String.IsNullOrEmpty(sortOrder) ? "name_desc" : ""; ViewBag.DateSortParm = sortOrder == "Date" ? "date_desc" : "Date"; var students = from s in db.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(students.ToList()); }
Ten kod odbiera sortOrder
parametr z ciągu zapytania w adresie URL. Wartość ciągu zapytania jest dostarczana przez ASP.NET MVC jako parametr metody akcji. Parametr jest ciągiem "Name" lub "Date", po którym opcjonalnie następuje podkreślenie i ciąg "desc", aby określić kolejność malejącą. Domyślna kolejność sortowania jest rosnąca.
Przy pierwszym żądaniu strony Indeks nie ma ciągu zapytania. Uczniowie są wyświetlani w kolejności rosnącej według LastName
, która jest domyślnie określona w przypadku fall-through w instrukcji switch
. Gdy użytkownik kliknie hiperlink nagłówka kolumny, w ciągu zapytania zostanie podana odpowiednia sortOrder
wartość.
Dwie ViewBag
zmienne są używane, aby widok mógł skonfigurować hiperlinki nagłówka kolumny z odpowiednimi wartościami ciągu zapytania:
ViewBag.NameSortParm = String.IsNullOrEmpty(sortOrder) ? "name_desc" : "";
ViewBag.DateSortParm = sortOrder == "Date" ? "date_desc" : "Date";
Są toternarne instrukcje. Pierwszy określa, że jeśli sortOrder
parametr ma wartość null lub jest pusty, ViewBag.NameSortParm
powinien być ustawiony na wartość "name_desc"; w przeciwnym razie należy ustawić go na pusty ciąg. Te dwie instrukcje umożliwiają widokowi ustawianie hiperlinków nagłówka kolumny w następujący sposób:
Bieżąca kolejność sortowania | Hiperłącze nazwisko | Hiperłącze daty |
---|---|---|
Nazwisko rosnąco | descending | ascending |
Nazwisko malejące | ascending | ascending |
Data rosnąca | ascending | descending |
Data malejąco | ascending | ascending |
Metoda używa LINQ to Entities, aby określić kolumnę do sortowania. Kod tworzy zmienną przed instrukcjąIQueryable<T>, modyfikuje ją w switch
instrukcji i wywołuje metodę ToList
po switch
instrukcji .switch
Podczas tworzenia i modyfikowania IQueryable
zmiennych żadne zapytanie nie jest wysyłane do bazy danych. Zapytanie nie jest wykonywane, dopóki obiekt nie zostanie przekonwertowany IQueryable
na kolekcję przez wywołanie metody, takiej jak ToList
. W związku z tym ten kod powoduje wykonanie pojedynczego zapytania, które nie zostanie wykonane, dopóki instrukcja nie zostanie return View
wykonana.
Alternatywą dla pisania różnych instrukcji LINQ dla każdej kolejności sortowania jest możliwość dynamicznego utworzenia instrukcji LINQ. Aby uzyskać informacje na temat dynamicznego LINQ, zobacz Dynamic LINQ (Dynamiczny LINQ).
Dodawanie hiperlinków nagłówków kolumn do widoku indeksu ucznia
W pliku Views\Student\Index.cshtml zastąp
<tr>
elementy i<th>
dla wiersza nagłówka wyróżnionym kodem:<p> @Html.ActionLink("Create New", "Create") </p> <table class="table"> <tr> <th> @Html.ActionLink("Last Name", "Index", new { sortOrder = ViewBag.NameSortParm }) </th> <th>First Name </th> <th> @Html.ActionLink("Enrollment Date", "Index", new { sortOrder = ViewBag.DateSortParm }) </th> <th></th> </tr> @foreach (var item in Model) {
Ten kod używa informacji we właściwościach
ViewBag
do konfigurowania hiperlinków z odpowiednimi wartościami ciągu zapytania.Uruchom stronę i kliknij nagłówki kolumn Last Name (Nazwisko ) i Enrollment Date (Data rejestracji ), aby sprawdzić, czy sortowanie działa.
Po kliknięciu nagłówka Nazwisko uczniowie są wyświetlani w kolejności malejącego nazwiska.
Dodawanie pola wyszukiwania
Aby dodać filtrowanie do strony indeksu Uczniowie, dodasz pole tekstowe i przycisk przesyłania do widoku i wprowadzisz odpowiednie zmiany w metodzie Index
. Pole tekstowe umożliwia wprowadzenie ciągu do wyszukania w polach imię i nazwisko.
Dodawanie funkcji filtrowania do metody Index
W pliku Controllers\StudentController.cs zastąp metodę
Index
następującym kodem (zmiany są wyróżnione):public ViewResult Index(string sortOrder, string searchString) { ViewBag.NameSortParm = String.IsNullOrEmpty(sortOrder) ? "name_desc" : ""; ViewBag.DateSortParm = sortOrder == "Date" ? "date_desc" : "Date"; var students = from s in db.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(students.ToList()); }
Kod dodaje searchString
parametr do Index
metody . Wartość ciągu wyszukiwania jest odbierana z pola tekstowego dodanego do widoku Indeks. Dodaje również klauzulę where
do instrukcji LINQ, która wybiera tylko uczniów, których imię lub nazwisko zawiera ciąg wyszukiwania. Instrukcja, która dodaje klauzulę Where , jest wykonywana tylko wtedy, gdy istnieje wartość do wyszukania.
Uwaga
W wielu przypadkach można wywołać tę samą metodę w zestawie jednostki Entity Framework lub jako metodę rozszerzenia w kolekcji w pamięci. Wyniki są zwykle takie same, ale w niektórych przypadkach mogą się różnić.
Na przykład implementacja Contains
.NET Framework metody zwraca wszystkie wiersze po przekazaniu do niego pustego ciągu, ale dostawca platformy Entity Framework dla SQL Server Compact 4.0 zwraca zero wierszy dla pustych ciągów. W związku z tym kod w przykładzie (umieszczenie Where
instrukcji wewnątrz if
instrukcji) zapewnia, że uzyskasz te same wyniki dla wszystkich wersji SQL Server. Ponadto implementacja Contains
.NET Framework metody domyślnie wykonuje porównanie uwzględniające wielkość liter, ale dostawcy platformy Entity Framework SQL Server domyślnie wykonują porównania bez uwzględniania wielkości liter. Dlatego wywołanie ToUpper
metody w celu jawnego uwzględniania wielkości liter w teście gwarantuje, że wyniki nie zmieniają się po zmianie kodu później w celu użycia repozytorium, które zwróci IEnumerable
kolekcję zamiast IQueryable
obiektu. (Po wywołaniu Contains
metody w IEnumerable
kolekcji uzyskujesz implementację .NET Framework; podczas wywoływania jej w IQueryable
obiekcie uzyskuje się implementację dostawcy bazy danych).
Obsługa wartości null może być również inna dla różnych dostawców bazy danych lub w przypadku użycia IQueryable
obiektu w porównaniu z użyciem IEnumerable
kolekcji. Na przykład w niektórych scenariuszach Where
warunek, taki jak table.Column != 0
może nie zwracać kolumn, które mają null
jako wartość. Domyślnie program EF generuje dodatkowe operatory SQL, aby zapewnić równość między wartościami null w bazie danych, tak jak działa w pamięci, ale można ustawić flagę UseDatabaseNullSemantics w ef6 lub wywołać metodę UseRelationalNulls w programie EF Core w celu skonfigurowania tego zachowania.
Dodawanie pola wyszukiwania do widoku indeksu ucznia
W pliku Views\Student\Index.cshtml dodaj wyróżniony kod bezpośrednio przed tagiem otwierania
table
, aby utworzyć podpis, pole tekstowe i przycisk Wyszukaj.<p> @Html.ActionLink("Create New", "Create") </p> @using (Html.BeginForm()) { <p> Find by name: @Html.TextBox("SearchString") <input type="submit" value="Search" /></p> } <table> <tr>
Uruchom stronę, wprowadź ciąg wyszukiwania, a następnie kliknij przycisk Wyszukaj , aby sprawdzić, czy filtrowanie działa.
Zwróć uwagę, że adres URL nie zawiera ciągu wyszukiwania "an", co oznacza, że w przypadku zakładki tej strony nie otrzymasz filtrowanej listy podczas korzystania z zakładki. Dotyczy to również linków sortowania kolumn, ponieważ będą sortować całą listę. W dalszej części samouczka zmienisz przycisk Wyszukaj , aby użyć ciągów zapytania do kryteriów filtrowania.
Dodawanie stronicowania
Aby dodać stronicowanie do strony indeksu Uczniowie, zaczniesz od zainstalowania pakietu NuGet PagedList.Mvc . Następnie wprowadzisz dodatkowe zmiany w metodzie Index
i dodasz linki stronicowania do Index
widoku. PagedList.Mvc jest jednym z wielu dobrych pakietów stronicowania i sortowania dla ASP.NET MVC, a jego użycie jest przeznaczone tylko jako przykład, a nie jako zalecenie dla niego w przypadku innych opcji.
Instalowanie pakietu NuGet PagedList.MVC
Pakiet NuGet PagedList.Mvc automatycznie instaluje pakiet PagedList jako zależność. Pakiet PagedList instaluje PagedList
metody typu kolekcji i rozszerzenia dla IQueryable
kolekcji i IEnumerable
. Metody rozszerzenia tworzą pojedynczą stronę danych w PagedList
kolekcji z elementu IQueryable
lub IEnumerable
, a PagedList
kolekcja udostępnia kilka właściwości i metod ułatwiających stronicowanie. Pakiet PagedList.Mvc instaluje pomocnika stronicowania, który wyświetla przyciski stronicowania.
W menu Narzędzia wybierz pozycję Menedżer pakietów NuGet , a następnie pozycję Konsola menedżera pakietów.
W oknie Konsola menedżera pakietów upewnij się, że źródło pakietu jest nuget.org , a domyślnym projektem jest ContosoUniversity, a następnie wprowadź następujące polecenie:
Install-Package PagedList.Mvc
Skompiluj projekt.
Uwaga
Pakiet PageList nie jest już utrzymywany. Dlatego w przypadku bieżących projektów lepiej jest użyć pakietu X.PagedList . Główną różnicą jest to, że X.PagedList jest przenośnym zestawem. Oznacza to, że pakiet jest międzyplatformowy i może być używany w projektach internetowych, a także w innych projektach platformy .NET. Nowy pakiet nie powinien powodować problemów ze zgodnością, ponieważ został on przekierowany do platformy .NET 6 od wersji 8.4.
Dodawanie funkcji stronicowania do metody Index
W pliku Controllers\StudentController.cs dodaj instrukcję
using
dlaPagedList
przestrzeni nazw:using PagedList;
Zastąp metodę
Index
poniższym kodem:public ViewResult Index(string sortOrder, string currentFilter, string searchString, int? page) { ViewBag.CurrentSort = sortOrder; ViewBag.NameSortParm = String.IsNullOrEmpty(sortOrder) ? "name_desc" : ""; ViewBag.DateSortParm = sortOrder == "Date" ? "date_desc" : "Date"; if (searchString != null) { page = 1; } else { searchString = currentFilter; } ViewBag.CurrentFilter = searchString; var students = from s in db.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: // Name ascending students = students.OrderBy(s => s.LastName); break; } int pageSize = 3; int pageNumber = (page ?? 1); return View(students.ToPagedList(pageNumber, pageSize)); }
Ten kod dodaje
page
parametr, bieżący parametr kolejności sortowania i bieżący parametr filtru do podpisu metody:public ActionResult Index(string sortOrder, string currentFilter, string searchString, int? page)
Przy pierwszym wyświetleniu strony lub jeśli użytkownik nie kliknął łącza stronicowania lub sortowania, wszystkie parametry mają wartość null. Po kliknięciu linku stronicowania zmienna
page
zawiera numer strony do wyświetlenia.Właściwość
ViewBag
udostępnia widok z bieżącą kolejnością sortowania, ponieważ musi ona być uwzględniona w linkach stronicowania, aby zachować kolejność sortowania tak samo podczas stronicowania:ViewBag.CurrentSort = sortOrder;
Inna właściwość ,
ViewBag.CurrentFilter
udostępnia widok z bieżącym ciągiem filtru. Ta wartość musi być uwzględniona w linkach stronicowania, aby zachować ustawienia filtru podczas stronicowania i należy ją przywrócić do pola tekstowego, gdy strona zostanie ponownie odtworzona. Jeśli ciąg wyszukiwania zostanie zmieniony podczas stronicowania, strona musi zostać zresetowana do wartości 1, ponieważ nowy filtr może spowodować wyświetlenie różnych danych. Ciąg wyszukiwania jest zmieniany po wprowadzeniu wartości w polu tekstowym i naciśnięciu przycisku przesyłania. W takim przypadkusearchString
parametr nie ma wartości null.if (searchString != null) { page = 1; } else { searchString = currentFilter; }
Na końcu metody
ToPagedList
metoda rozszerzenia obiektu studentsIQueryable
konwertuje zapytanie ucznia na jedną stronę uczniów w typie kolekcji, który obsługuje stronicowanie. Ta pojedyncza strona uczniów jest następnie przekazywana do widoku:int pageSize = 3; int pageNumber = (page ?? 1); return View(students.ToPagedList(pageNumber, pageSize));
Metoda
ToPagedList
przyjmuje numer strony. Dwa znaki zapytania reprezentują operator łączenia wartości null. Operator łączenia wartości null definiuje wartość domyślną dla typu dopuszczającego wartość null; wyrażenie(page ?? 1)
oznacza, że zwraca wartośćpage
, jeśli ma wartość, lub zwraca wartość 1, jeślipage
ma wartość null.
Dodawanie linków stronicowania do widoku indeksu ucznia
W pliku Views\Student\Index.cshtml zastąp istniejący kod następującym kodem. Zmiany są wyróżnione.
@model PagedList.IPagedList<ContosoUniversity.Models.Student> @using PagedList.Mvc; <link href="~/Content/PagedList.css" rel="stylesheet" type="text/css" /> @{ ViewBag.Title = "Students"; } <h2>Students</h2> <p> @Html.ActionLink("Create New", "Create") </p> @using (Html.BeginForm("Index", "Student", FormMethod.Get)) { <p> Find by name: @Html.TextBox("SearchString", ViewBag.CurrentFilter as string) <input type="submit" value="Search" /> </p> } <table class="table"> <tr> <th> @Html.ActionLink("Last Name", "Index", new { sortOrder = ViewBag.NameSortParm, currentFilter=ViewBag.CurrentFilter }) </th> <th> First Name </th> <th> @Html.ActionLink("Enrollment Date", "Index", new { sortOrder = ViewBag.DateSortParm, currentFilter=ViewBag.CurrentFilter }) </th> <th></th> </tr> @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> @Html.ActionLink("Edit", "Edit", new { id=item.ID }) | @Html.ActionLink("Details", "Details", new { id=item.ID }) | @Html.ActionLink("Delete", "Delete", new { id=item.ID }) </td> </tr> } </table> <br /> Page @(Model.PageCount < Model.PageNumber ? 0 : Model.PageNumber) of @Model.PageCount @Html.PagedListPager(Model, page => Url.Action("Index", new { page, sortOrder = ViewBag.CurrentSort, currentFilter = ViewBag.CurrentFilter }))
Instrukcja
@model
w górnej części strony określa, że widok pobieraPagedList
teraz obiekt zamiastList
obiektu.Instrukcja
using
dlaPagedList.Mvc
elementu zapewnia dostęp do pomocnika MVC dla przycisków stronicowania.Kod używa przeciążenia elementu BeginForm , które umożliwia określenie metody FormMethod.Get.
@using (Html.BeginForm("Index", "Student", FormMethod.Get)) { <p> Find by name: @Html.TextBox("SearchString", ViewBag.CurrentFilter as string) <input type="submit" value="Search" /> </p> }
Domyślny formularz BeginForm przesyła dane formularza za pomocą funkcji POST, co oznacza, że parametry są przekazywane w treści komunikatu HTTP, a nie w adresie URL jako ciągi zapytania. Po określeniu żądania HTTP GET dane formularza są przekazywane w adresie URL jako ciągi zapytania, co umożliwia użytkownikom dodawanie zakładek adresu URL. Wytyczne dotyczące W3C dotyczące korzystania z żądania HTTP GET zaleca się użycie polecenia GET, gdy akcja nie spowoduje aktualizacji.
Pole tekstowe jest inicjowane przy użyciu bieżącego ciągu wyszukiwania, więc po kliknięciu nowej strony można zobaczyć bieżący ciąg wyszukiwania.
Find by name: @Html.TextBox("SearchString", ViewBag.CurrentFilter as string)
Linki nagłówka kolumny używają ciągu zapytania, aby przekazać bieżący ciąg wyszukiwania do kontrolera, aby użytkownik mógł sortować wyniki filtru:
@Html.ActionLink("Last Name", "Index", new { sortOrder=ViewBag.NameSortParm, currentFilter=ViewBag.CurrentFilter })
Wyświetlana jest bieżąca strona i łączna liczba stron.
Page @(Model.PageCount < Model.PageNumber ? 0 : Model.PageNumber) of @Model.PageCount
Jeśli nie ma stron do wyświetlenia, zostanie wyświetlona wartość "Strona 0 z 0". (W takim przypadku numer strony jest większy niż liczba stron, ponieważ
Model.PageNumber
wynosi 1 iModel.PageCount
wynosi 0).Przyciski stronicowania są wyświetlane przez
PagedListPager
pomocnika:@Html.PagedListPager( Model, page => Url.Action("Index", new { page }) )
Pomocnik
PagedListPager
udostępnia szereg opcji, które można dostosować, w tym adresy URL i style. Aby uzyskać więcej informacji, zobacz TroyGoode / PagedList w witrynie GitHub.Uruchom stronę.
Kliknij łącza stronicowania w różnych kolejności sortowania, aby upewnić się, że stronicowanie działa. Następnie wprowadź ciąg wyszukiwania i spróbuj ponownie stronicować, aby sprawdzić, czy stronicowanie działa również poprawnie z sortowaniem i filtrowaniem.
Tworzenie strony Informacje
Na stronie Informacje o witrynie internetowej Contoso University zobaczysz, ilu studentów zarejestrowało się dla każdej daty rejestracji. Wymaga to grupowania i prostych obliczeń w grupach. W tym celu należy wykonać następujące czynności:
- Utwórz klasę modelu widoku dla danych, które należy przekazać do widoku.
- Zmodyfikuj metodę
About
w kontrolerzeHome
. - Zmodyfikuj
About
widok.
Tworzenie modelu widoku
Utwórz folder ViewModels w folderze projektu. W tym folderze dodaj plik klasy EnrollmentDateGroup.cs i zastąp kod szablonu następującym kodem:
using System;
using System.ComponentModel.DataAnnotations;
namespace ContosoUniversity.ViewModels
{
public class EnrollmentDateGroup
{
[DataType(DataType.Date)]
public DateTime? EnrollmentDate { get; set; }
public int StudentCount { get; set; }
}
}
Modyfikowanie kontrolera głównego
W pliku HomeController.cs dodaj następujące
using
instrukcje w górnej części pliku:using ContosoUniversity.DAL; using ContosoUniversity.ViewModels;
Dodaj zmienną klasy dla kontekstu bazy danych natychmiast po otwarciu nawiasu klamrowego dla klasy:
public class HomeController : Controller { private SchoolContext db = new SchoolContext();
Zastąp metodę
About
poniższym kodem:public ActionResult About() { IQueryable<EnrollmentDateGroup> data = from student in db.Students group student by student.EnrollmentDate into dateGroup select new EnrollmentDateGroup() { EnrollmentDate = dateGroup.Key, StudentCount = dateGroup.Count() }; return View(data.ToList()); }
Instrukcja LINQ grupuje jednostki uczniów według daty rejestracji, oblicza liczbę jednostek w każdej grupie i przechowuje wyniki w kolekcji
EnrollmentDateGroup
obiektów modelu widoku.Dodaj metodę
Dispose
:protected override void Dispose(bool disposing) { db.Dispose(); base.Dispose(disposing); }
Modyfikowanie widoku Informacje
Zastąp kod w pliku Views\Home\About.cshtml następującym kodem:
@model IEnumerable<ContosoUniversity.ViewModels.EnrollmentDateGroup> @{ ViewBag.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>
Uruchom aplikację i kliknij link Informacje .
Liczba uczniów dla każdej daty rejestracji jest wyświetlana w tabeli.
Uzyskiwanie kodu
Pobieranie ukończonego projektu
Dodatkowe zasoby
Linki do innych zasobów programu Entity Framework można znaleźć w ASP.NET Dostęp do danych — zalecane zasoby.
Następne kroki
W tym samouczku zostały wykonane następujące czynności:
- Dodawanie łączy sortowania kolumn
- Dodawanie pola wyszukiwania
- Dodawanie stronicowania
- Tworzenie strony Informacje
Przejdź do następnego artykułu, aby dowiedzieć się, jak używać odporności połączenia i przechwytywania poleceń.
Opinia
https://aka.ms/ContentUserFeedback.
Dostępne już wkrótce: W 2024 r. będziemy stopniowo wycofywać zgłoszenia z serwisu GitHub jako mechanizm przesyłania opinii na temat zawartości i zastępować go nowym systemem opinii. Aby uzyskać więcej informacji, sprawdź:Prześlij i wyświetl opinię dla