Bölüm 3, Razor ASP.NET Çekirdeğinde olan EF Core sayfalar - Sıralama, Filtreleme, Sayfalama
Tom Dykstra, Jeremy Likness ve Jon P Smith tarafından
Contoso University web uygulaması, ve Visual Studio kullanarak EF Core Sayfalar web uygulamalarının nasıl oluşturulacağını Razor gösterir. Öğretici serisi hakkında bilgi için ilk öğreticiye bakın.
Çözemediğiniz sorunlarla karşılaşırsanız, tamamlanmış uygulamayı indirin ve öğreticiyi izleyerek bu kodu oluşturduğunuz kodla karşılaştırın.
Bu öğretici, Öğrenciler sayfalarına sıralama, filtreleme ve sayfalama işlevleri ekler.
Aşağıdaki çizimde tamamlanmış bir sayfa gösterilmektedir. Sütun başlıkları, sütunu sıralamak için tıklanabilir bağlantılardır. Artan ve azalan sıralama düzeni arasında geçiş yapmak için art arda bir sütun başlığına tıklayın.
Sıralama ekleme
Sıralama eklemek için içindeki Pages/Students/Index.cshtml.cs
kodu aşağıdaki kodla değiştirin.
public class IndexModel : PageModel
{
private readonly SchoolContext _context;
public IndexModel(SchoolContext context)
{
_context = context;
}
public string NameSort { get; set; }
public string DateSort { get; set; }
public string CurrentFilter { get; set; }
public string CurrentSort { get; set; }
public IList<Student> Students { get; set; }
public async Task OnGetAsync(string sortOrder)
{
// using System;
NameSort = String.IsNullOrEmpty(sortOrder) ? "name_desc" : "";
DateSort = sortOrder == "Date" ? "date_desc" : "Date";
IQueryable<Student> studentsIQ = from s in _context.Students
select s;
switch (sortOrder)
{
case "name_desc":
studentsIQ = studentsIQ.OrderByDescending(s => s.LastName);
break;
case "Date":
studentsIQ = studentsIQ.OrderBy(s => s.EnrollmentDate);
break;
case "date_desc":
studentsIQ = studentsIQ.OrderByDescending(s => s.EnrollmentDate);
break;
default:
studentsIQ = studentsIQ.OrderBy(s => s.LastName);
break;
}
Students = await studentsIQ.AsNoTracking().ToListAsync();
}
}
Yukarıdaki kod:
- eklenmesini
using System;
gerektirir. - Sıralama parametrelerini içerecek özellikler ekler.
- özelliğinin
Student
adını olarakStudents
değiştirir. - yöntemindeki
OnGetAsync
kodu değiştirir.
yöntemi, URL'deki OnGetAsync
sorgu dizesinden bir sortOrder
parametre alır. URL ve sorgu dizesi, Bağlayıcı Etiketi Yardımcısı tarafından oluşturulur.
sortOrder
parametresi veya Name
Date
şeklindedir. Azalan sortOrder
sırayı belirtmek için isteğe bağlı olarak parametresini _desc
takip edilir. Varsayılan sıralama düzeni artan düzendedir.
Öğrenciler bağlantısından Dizin sayfası istendiğinde sorgu dizesi yoktur. Öğrenciler soyadına göre artan düzende görüntülenir. Soyadına göre artan düzen deyimindekidir default
switch
. Kullanıcı bir sütun başlığı bağlantısına tıkladığında, sorgu dizesi değerinde uygun sortOrder
değer sağlanır.
NameSort
ve DateSort
Sayfa tarafından Razor sütun başlığı köprülerini uygun sorgu dizesi değerleriyle yapılandırmak için kullanılır:
NameSort = String.IsNullOrEmpty(sortOrder) ? "name_desc" : "";
DateSort = sortOrder == "Date" ? "date_desc" : "Date";
Kod, C# koşullu işlecini ?: kullanır. işleci ?:
bir üçüncül işleçtir ve üç işlenen alır. İlk satır null veya boş olduğunda sortOrder
olarak NameSort
ayarlandığını name_desc
belirtir. Null veya boş değilsesortOrder
, NameSort
boş bir dizeye ayarlanır.
Bu iki deyim, sayfanın sütun başlığı köprülerini aşağıdaki gibi ayarlamasını sağlar:
Geçerli sıralama düzeni | Soyadı Köprüsü | Tarih Köprüsü |
---|---|---|
Soyadı artan | azalan düzende | ascending |
Soyadı azalan | ascending | ascending |
Artan tarih | ascending | azalan düzende |
Azalan tarih | ascending | ascending |
yöntemi, sıralama ölçütü olarak sütunu belirtmek için LINQ to Entities kullanır. Kod switch deyiminden önce bir IQueryable<Student>
başlatır ve switch deyiminde değiştirir:
IQueryable<Student> studentsIQ = from s in _context.Students
select s;
switch (sortOrder)
{
case "name_desc":
studentsIQ = studentsIQ.OrderByDescending(s => s.LastName);
break;
case "Date":
studentsIQ = studentsIQ.OrderBy(s => s.EnrollmentDate);
break;
case "date_desc":
studentsIQ = studentsIQ.OrderByDescending(s => s.EnrollmentDate);
break;
default:
studentsIQ = studentsIQ.OrderBy(s => s.LastName);
break;
}
Students = await studentsIQ.AsNoTracking().ToListAsync();
bir IQueryable
oluşturulduğunda veya değiştirildiğinde veritabanına hiçbir sorgu gönderilmez. Nesne bir koleksiyona dönüştürülene kadar IQueryable
sorgu yürütülemez. IQueryable
gibi ToListAsync
bir yöntemi çağırarak bir koleksiyona dönüştürülür. Bu nedenle kod, aşağıdaki deyime IQueryable
kadar yürütülmeyen tek bir sorguyla sonuçlanmıştır:
Students = await studentsIQ.AsNoTracking().ToListAsync();
OnGetAsync
çok sayıda sıralanabilir sütunla ayrıntılı olabilir. Bu işlevi kod etmenin alternatif bir yolu hakkında bilgi için bkz . Bu öğretici serisinin MVC sürümünde kodu basitleştirmek için dinamik LINQ kullanma.
Öğrenci Dizini sayfasına sütun başlığı köprüleri ekleme
içindeki Students/Index.cshtml
kodu aşağıdaki kodla değiştirin. Değişiklikler vurgulanır.
@page
@model ContosoUniversity.Pages.Students.IndexModel
@{
ViewData["Title"] = "Students";
}
<h2>Students</h2>
<p>
<a asp-page="Create">Create New</a>
</p>
<table class="table">
<thead>
<tr>
<th>
<a asp-page="./Index" asp-route-sortOrder="@Model.NameSort">
@Html.DisplayNameFor(model => model.Students[0].LastName)
</a>
</th>
<th>
@Html.DisplayNameFor(model => model.Students[0].FirstMidName)
</th>
<th>
<a asp-page="./Index" asp-route-sortOrder="@Model.DateSort">
@Html.DisplayNameFor(model => model.Students[0].EnrollmentDate)
</a>
</th>
<th></th>
</tr>
</thead>
<tbody>
@foreach (var item in Model.Students)
{
<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-page="./Edit" asp-route-id="@item.ID">Edit</a> |
<a asp-page="./Details" asp-route-id="@item.ID">Details</a> |
<a asp-page="./Delete" asp-route-id="@item.ID">Delete</a>
</td>
</tr>
}
</tbody>
</table>
Yukarıdaki kod:
- ve
EnrollmentDate
sütun başlıklarınaLastName
köprü ekler. - geçerli sıralama düzeni değerleriyle köprüler ayarlamak için ve
DateSort
içindeki bilgileriNameSort
kullanır. - Sayfa başlığını Dizinden Öğrenciler olarak değiştirir.
- olarak
Model.Students
değiştirilirModel.Student
.
Sıralamanın çalıştığını doğrulamak için:
- Uygulamayı çalıştırın ve Öğrenciler sekmesini seçin.
- Sütun başlıklarına tıklayın.
Filtreleme ekleme
Öğrenci Dizini sayfasına filtreleme eklemek için:
- Sayfaya Razor bir metin kutusu ve gönder düğmesi eklenir. Metin kutusu, ad veya soyadı üzerinde bir arama dizesi sağlar.
- Sayfa modeli, metin kutusu değerini kullanacak şekilde güncelleştirilir.
OnGetAsync yöntemini güncelleştirme
filtreleme eklemek için içindeki Students/Index.cshtml.cs
kodu aşağıdaki kodla değiştirin:
public class IndexModel : PageModel
{
private readonly SchoolContext _context;
public IndexModel(SchoolContext context)
{
_context = context;
}
public string NameSort { get; set; }
public string DateSort { get; set; }
public string CurrentFilter { get; set; }
public string CurrentSort { get; set; }
public IList<Student> Students { get; set; }
public async Task OnGetAsync(string sortOrder, string searchString)
{
NameSort = String.IsNullOrEmpty(sortOrder) ? "name_desc" : "";
DateSort = sortOrder == "Date" ? "date_desc" : "Date";
CurrentFilter = searchString;
IQueryable<Student> studentsIQ = from s in _context.Students
select s;
if (!String.IsNullOrEmpty(searchString))
{
studentsIQ = studentsIQ.Where(s => s.LastName.Contains(searchString)
|| s.FirstMidName.Contains(searchString));
}
switch (sortOrder)
{
case "name_desc":
studentsIQ = studentsIQ.OrderByDescending(s => s.LastName);
break;
case "Date":
studentsIQ = studentsIQ.OrderBy(s => s.EnrollmentDate);
break;
case "date_desc":
studentsIQ = studentsIQ.OrderByDescending(s => s.EnrollmentDate);
break;
default:
studentsIQ = studentsIQ.OrderBy(s => s.LastName);
break;
}
Students = await studentsIQ.AsNoTracking().ToListAsync();
}
}
Yukarıdaki kod:
- parametresini
searchString
yöntemineOnGetAsync
ekler ve parametre değerini özelliğineCurrentFilter
kaydeder. Arama dizesi değeri, sonraki bölümde eklenen bir metin kutusundan alınır. - LINQ deyimine bir
Where
yan tümcesi ekler.Where
yan tümcesi yalnızca ad veya soyadı arama dizesini içeren öğrencileri seçer. LINQ deyimi yalnızca aranacak bir değer varsa yürütülür.
IQueryable ve IEnumerable karşılaştırması
Kod bir IQueryable
nesnede Where yöntemini çağırır ve filtre sunucuda işlenir. Bazı senaryolarda uygulama, yöntemini bellek içi bir koleksiyonda uzantı yöntemi olarak çağırıyor Where
olabilir. Örneğin, öğesinin bir koleksiyon döndüren IEnumerable
bir depo yöntemine değiştiğini varsayalım_context.Students
.EF CoreDbSet
Sonuç normalde aynı olur ancak bazı durumlarda farklı olabilir.
Örneğin, .NET Framework uygulaması Contains
varsayılan olarak büyük/küçük harfe duyarlı bir karşılaştırma gerçekleştirir. SQL Server'da büyük/küçük harf duyarlılığı, Contains
SQL Server örneğinin harmanlama ayarı tarafından belirlenir. SQL Server varsayılan olarak büyük/küçük harfe duyarlı değildir. SQLite varsayılan olarak büyük/küçük harfe duyarlıdır. ToUpper
testi açıkça büyük/küçük harfe duyarsız hale getirmek için çağrılabilir:
Where(s => s.LastName.ToUpper().Contains(searchString.ToUpper())`
Yukarıdaki kod, yöntem bir veya IEnumerable
SQLite üzerinde çalıştırıldığında bile filtrenin Where
büyük/küçük harfe duyarlı olmamasını sağlar.
Bir IEnumerable
koleksiyonda çağrıldığında Contains
.NET Core uygulaması kullanılır. Bir IQueryable
nesnede çağrıldığında Contains
veritabanı uygulaması kullanılır.
genellikle Contains
performans nedenleriyle çağrısı IQueryable
tercih edilir. ile IQueryable
, filtreleme veritabanı sunucusu tarafından gerçekleştirilir. Önce bir IEnumerable
oluşturulursa, tüm satırların veritabanı sunucusundan döndürülür.
çağrısı ToUpper
için bir performans cezası vardır. Kod, ToUpper
TSQL SELECT deyiminin WHERE yan tümcesine bir işlev ekler. Eklenen işlev, iyileştiricinin dizin kullanmasını engeller. SQL'in büyük/küçük harfe duyarsız olarak yüklendiği düşünüldüğünde, gerekmediğinde çağrıdan ToUpper
kaçınmak en iyisidir.
Daha fazla bilgi için bkz . Sqlite sağlayıcısıyla büyük/küçük harfe duyarsız sorgu kullanma.
Sayfayı Razor güncelleştirme
Arama düğmesi eklemek için içindeki Pages/Students/Index.cshtml
kodu değiştirin.
@page
@model ContosoUniversity.Pages.Students.IndexModel
@{
ViewData["Title"] = "Students";
}
<h2>Students</h2>
<p>
<a asp-page="Create">Create New</a>
</p>
<form asp-page="./Index" method="get">
<div class="form-actions no-color">
<p>
Find by name:
<input type="text" name="SearchString" value="@Model.CurrentFilter" />
<input type="submit" value="Search" class="btn btn-primary" /> |
<a asp-page="./Index">Back to full List</a>
</p>
</div>
</form>
<table class="table">
<thead>
<tr>
<th>
<a asp-page="./Index" asp-route-sortOrder="@Model.NameSort">
@Html.DisplayNameFor(model => model.Students[0].LastName)
</a>
</th>
<th>
@Html.DisplayNameFor(model => model.Students[0].FirstMidName)
</th>
<th>
<a asp-page="./Index" asp-route-sortOrder="@Model.DateSort">
@Html.DisplayNameFor(model => model.Students[0].EnrollmentDate)
</a>
</th>
<th></th>
</tr>
</thead>
<tbody>
@foreach (var item in Model.Students)
{
<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-page="./Edit" asp-route-id="@item.ID">Edit</a> |
<a asp-page="./Details" asp-route-id="@item.ID">Details</a> |
<a asp-page="./Delete" asp-route-id="@item.ID">Delete</a>
</td>
</tr>
}
</tbody>
</table>
Yukarıdaki kod, arama metin kutusunu ve düğmesini eklemek için etiket yardımcısını kullanır <form>
. Varsayılan olarak, <form>
etiket yardımcısı form verilerini post ile gönderir. POST ile, parametreler URL'de değil HTTP ileti gövdesinde geçirilir. HTTP GET kullanıldığında, form verileri URL'ye sorgu dizeleri olarak geçirilir. Verileri sorgu dizeleriyle geçirmek, kullanıcıların URL'ye yer işareti eklemesine olanak tanır. W3C yönergeleri, eylem güncelleştirmeyle sonuçlanmadığında GET kullanılmasını önerir.
Uygulamayı test edin:
Öğrenciler sekmesini seçin ve bir arama dizesi girin. SQLite kullanıyorsanız, filtre yalnızca daha önce gösterilen isteğe bağlı
ToUpper
kodu uyguladıysanız büyük/küçük harfe duyarlı değildir.Ara'yı seçin.
URL'nin arama dizesini içerdiğine dikkat edin. Örneğin:
https://localhost:5001/Students?SearchString=an
Sayfaya yer işareti eklenirse, yer işareti sayfanın URL'sini ve sorgu dizesini SearchString
içerir. method="get"
etiketindekiform
, sorgu dizesinin oluşturulmasına neden olandır.
Şu anda, bir sütun başlığı sıralama bağlantısı seçildiğinde, Arama kutusundaki filtre değeri kaybolur. Kayıp filtre değeri bir sonraki bölümde düzeltildi.
Sayfalama ekleme
Bu bölümde, disk belleğini desteklemek için bir PaginatedList
sınıf oluşturulur. PaginatedList
sınıfı, tablonun tüm satırlarını almak yerine sunucudaki verileri filtrelemek için ve Take
deyimlerini kullanırSkip
. Aşağıdaki çizimde sayfalama düğmeleri gösterilmektedir.
PaginatedList sınıfını oluşturma
Proje klasöründe aşağıdaki kodla oluşturun PaginatedList.cs
:
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);
}
}
}
Yukarıdaki CreateAsync
koddaki yöntem sayfa boyutunu ve sayfa numarasını alır ve uygun Skip
ve Take
deyimlerini öğesine IQueryable
uygular. üzerinde IQueryable
çağrıldığındaToListAsync
, yalnızca istenen sayfayı içeren bir Liste döndürür. ve özellikleri HasPreviousPage
HasNextPage
, Önceki ve Sonraki sayfalama düğmelerini etkinleştirmek veya devre dışı bırakmak için kullanılır.
CreateAsync
yöntemi, oluşturmak PaginatedList<T>
için kullanılır. Oluşturucu nesneyi oluşturamaz PaginatedList<T>
; oluşturucular zaman uyumsuz kod çalıştıramaz.
Yapılandırmaya sayfa boyutu ekleme
appsettings.json
Yapılandırma dosyasına ekleyinPageSize
:
{
"PageSize": 3,
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information"
}
},
"AllowedHosts": "*",
"ConnectionStrings": {
"SchoolContext": "Server=(localdb)\\mssqllocaldb;Database=CU-1;Trusted_Connection=True;MultipleActiveResultSets=true"
}
}
IndexModel'e disk belleği ekleme
disk belleği eklemek için içindeki Students/Index.cshtml.cs
kodu değiştirin.
using ContosoUniversity.Data;
using ContosoUniversity.Models;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using System;
using System.Linq;
using System.Threading.Tasks;
namespace ContosoUniversity.Pages.Students
{
public class IndexModel : PageModel
{
private readonly SchoolContext _context;
private readonly IConfiguration Configuration;
public IndexModel(SchoolContext context, IConfiguration configuration)
{
_context = context;
Configuration = configuration;
}
public string NameSort { get; set; }
public string DateSort { get; set; }
public string CurrentFilter { get; set; }
public string CurrentSort { get; set; }
public PaginatedList<Student> Students { get; set; }
public async Task OnGetAsync(string sortOrder,
string currentFilter, string searchString, int? pageIndex)
{
CurrentSort = sortOrder;
NameSort = String.IsNullOrEmpty(sortOrder) ? "name_desc" : "";
DateSort = sortOrder == "Date" ? "date_desc" : "Date";
if (searchString != null)
{
pageIndex = 1;
}
else
{
searchString = currentFilter;
}
CurrentFilter = searchString;
IQueryable<Student> studentsIQ = from s in _context.Students
select s;
if (!String.IsNullOrEmpty(searchString))
{
studentsIQ = studentsIQ.Where(s => s.LastName.Contains(searchString)
|| s.FirstMidName.Contains(searchString));
}
switch (sortOrder)
{
case "name_desc":
studentsIQ = studentsIQ.OrderByDescending(s => s.LastName);
break;
case "Date":
studentsIQ = studentsIQ.OrderBy(s => s.EnrollmentDate);
break;
case "date_desc":
studentsIQ = studentsIQ.OrderByDescending(s => s.EnrollmentDate);
break;
default:
studentsIQ = studentsIQ.OrderBy(s => s.LastName);
break;
}
var pageSize = Configuration.GetValue("PageSize", 4);
Students = await PaginatedList<Student>.CreateAsync(
studentsIQ.AsNoTracking(), pageIndex ?? 1, pageSize);
}
}
}
Yukarıdaki kod:
- özelliğinin
Students
türünü olarakIList<Student>
PaginatedList<Student>
değiştirir. - Sayfa dizinini, geçerli
sortOrder
ve öğesinicurrentFilter
yöntem imzasınaOnGetAsync
ekler. - Sıralama düzenini özelliğine
CurrentSort
kaydeder. - Yeni bir arama dizesi olduğunda sayfa dizinini 1 olarak sıfırlar.
- Öğrenci varlıklarını almak için sınıfını
PaginatedList
kullanır. - Yapılandırma başarısız olursa Yapılandırma'dan 3, 4 olarak ayarlar
pageSize
.
Aşağıdaki durumlarda, alan tüm parametreler OnGetAsync
null olur:
- Sayfa, Öğrenciler bağlantısından çağrılır.
- Kullanıcı bir sayfalama veya sıralama bağlantısına tıklamadı.
Sayfalama bağlantısına tıklandığında, sayfa dizini değişkeni görüntülenecek sayfa numarasını içerir.
özelliği Sayfaya CurrentSort
Razor geçerli sıralama düzenini sağlar. Sayfalama sırasında sıralama düzenini korumak için geçerli sıralama düzeninin sayfalama bağlantılarına eklenmesi gerekir.
özelliği Sayfaya CurrentFilter
Razor geçerli filtre dizesini sağlar. Değer CurrentFilter
:
- Disk belleği sırasında filtre ayarlarını korumak için sayfalama bağlantılarına eklenmelidir.
- Sayfa yeniden görüntülendiğinde metin kutusuna geri yüklenmelidir.
Sayfalama sırasında arama dizesi değiştirilirse sayfa 1'e sıfırlanır. Yeni filtre farklı verilerin görüntülenmesine neden olabileceğinden sayfanın 1'e sıfırlanması gerekir. Arama değeri girildiğinde ve Gönder seçildiğinde:
- Arama dizesi değiştirilir.
searchString
Parametresi null değil.
yöntemi, PaginatedList.CreateAsync
öğrenci sorgusunu disk belleğini destekleyen bir koleksiyon türündeki tek bir öğrenci sayfasına dönüştürür. Tek bir öğrenci sayfası Sayfaya Razor geçirilir.
Çağrısından PaginatedList.CreateAsync
sonraki pageIndex
iki soru işareti null birleşim işlecini temsil eder. Null birleşim işleci, null atanabilir bir tür için varsayılan değeri tanımlar. İfade pageIndex ?? 1
, değeri pageIndex
varsa değerini döndürür, aksi takdirde 1 döndürür.
Sayfalama bağlantıları ekleme
Students/Index.cshtml
içindeki kodu aşağıdaki kodla değiştirin. Değişiklikler vurgulanır:
@page
@model ContosoUniversity.Pages.Students.IndexModel
@{
ViewData["Title"] = "Students";
}
<h2>Students</h2>
<p>
<a asp-page="Create">Create New</a>
</p>
<form asp-page="./Index" method="get">
<div class="form-actions no-color">
<p>
Find by name:
<input type="text" name="SearchString" value="@Model.CurrentFilter" />
<input type="submit" value="Search" class="btn btn-primary" /> |
<a asp-page="./Index">Back to full List</a>
</p>
</div>
</form>
<table class="table">
<thead>
<tr>
<th>
<a asp-page="./Index" asp-route-sortOrder="@Model.NameSort"
asp-route-currentFilter="@Model.CurrentFilter">
@Html.DisplayNameFor(model => model.Students[0].LastName)
</a>
</th>
<th>
@Html.DisplayNameFor(model => model.Students[0].FirstMidName)
</th>
<th>
<a asp-page="./Index" asp-route-sortOrder="@Model.DateSort"
asp-route-currentFilter="@Model.CurrentFilter">
@Html.DisplayNameFor(model => model.Students[0].EnrollmentDate)
</a>
</th>
<th></th>
</tr>
</thead>
<tbody>
@foreach (var item in Model.Students)
{
<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-page="./Edit" asp-route-id="@item.ID">Edit</a> |
<a asp-page="./Details" asp-route-id="@item.ID">Details</a> |
<a asp-page="./Delete" asp-route-id="@item.ID">Delete</a>
</td>
</tr>
}
</tbody>
</table>
@{
var prevDisabled = !Model.Students.HasPreviousPage ? "disabled" : "";
var nextDisabled = !Model.Students.HasNextPage ? "disabled" : "";
}
<a asp-page="./Index"
asp-route-sortOrder="@Model.CurrentSort"
asp-route-pageIndex="@(Model.Students.PageIndex - 1)"
asp-route-currentFilter="@Model.CurrentFilter"
class="btn btn-primary @prevDisabled">
Previous
</a>
<a asp-page="./Index"
asp-route-sortOrder="@Model.CurrentSort"
asp-route-pageIndex="@(Model.Students.PageIndex + 1)"
asp-route-currentFilter="@Model.CurrentFilter"
class="btn btn-primary @nextDisabled">
Next
</a>
Sütun üst bilgisi bağlantıları, geçerli arama dizesini yöntemine geçirmek için sorgu dizesini OnGetAsync
kullanır:
<a asp-page="./Index" asp-route-sortOrder="@Model.NameSort"
asp-route-currentFilter="@Model.CurrentFilter">
@Html.DisplayNameFor(model => model.Students[0].LastName)
</a>
Sayfalama düğmeleri etiket yardımcıları tarafından görüntülenir:
<a asp-page="./Index"
asp-route-sortOrder="@Model.CurrentSort"
asp-route-pageIndex="@(Model.Students.PageIndex - 1)"
asp-route-currentFilter="@Model.CurrentFilter"
class="btn btn-primary @prevDisabled">
Previous
</a>
<a asp-page="./Index"
asp-route-sortOrder="@Model.CurrentSort"
asp-route-pageIndex="@(Model.Students.PageIndex + 1)"
asp-route-currentFilter="@Model.CurrentFilter"
class="btn btn-primary @nextDisabled">
Next
</a>
Uygulamayı çalıştırın ve öğrenciler sayfasına gidin.
- Sayfalamanın çalıştığından emin olmak için farklı sıralama düzenlerindeki sayfalama bağlantılarına tıklayın.
- Sayfalamanın sıralama ve filtreleme ile doğru şekilde çalıştığını doğrulamak için bir arama dizesi girin ve sayfalandırmayı deneyin.
Gruplama
Bu bölüm, her kayıt tarihi için kaç öğrencinin kaydolduğunu gösteren bir About
sayfa oluşturur. Güncelleştirme gruplandırma kullanır ve aşağıdaki adımları içerir:
- Sayfa tarafından
About
kullanılan veriler için bir görünüm modeli oluşturun. About
Görünüm modelini kullanmak için sayfayı güncelleştirin.
Görünüm modelini oluşturma
Models/SchoolViewModels klasörü oluşturun.
Aşağıdaki kodla oluşturun SchoolViewModels/EnrollmentDateGroup.cs
:
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; }
}
}
Sayfayı Razor Oluşturma
Aşağıdaki kodla bir Pages/About.cshtml
dosya oluşturun:
@page
@model ContosoUniversity.Pages.AboutModel
@{
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.Students)
{
<tr>
<td>
@Html.DisplayFor(modelItem => item.EnrollmentDate)
</td>
<td>
@item.StudentCount
</td>
</tr>
}
</table>
Sayfa modelini oluşturma
Pages/About.cshtml.cs
Dosyayı aşağıdaki kodla güncelleştirin:
using ContosoUniversity.Models.SchoolViewModels;
using ContosoUniversity.Data;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.EntityFrameworkCore;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using ContosoUniversity.Models;
namespace ContosoUniversity.Pages
{
public class AboutModel : PageModel
{
private readonly SchoolContext _context;
public AboutModel(SchoolContext context)
{
_context = context;
}
public IList<EnrollmentDateGroup> Students { get; set; }
public async Task OnGetAsync()
{
IQueryable<EnrollmentDateGroup> data =
from student in _context.Students
group student by student.EnrollmentDate into dateGroup
select new EnrollmentDateGroup()
{
EnrollmentDate = dateGroup.Key,
StudentCount = dateGroup.Count()
};
Students = await data.AsNoTracking().ToListAsync();
}
}
}
LINQ deyimi, öğrenci varlıklarını kayıt tarihine göre gruplandırır, her gruptaki varlık sayısını hesaplar ve sonuçları bir görünüm modeli nesneleri koleksiyonunda EnrollmentDateGroup
depolar.
Uygulamayı çalıştırın ve Hakkında sayfasına gidin. Her kayıt tarihi için öğrenci sayısı bir tabloda görüntülenir.
Sonraki adımlar
Sonraki öğreticide uygulama, veri modelini güncelleştirmek için geçişleri kullanır.
Bu öğreticide sıralama, filtreleme, gruplandırma ve sayfalama işlevleri eklenir.
Aşağıdaki çizimde tamamlanmış bir sayfa gösterilmektedir. Sütun başlıkları, sütunu sıralamak için tıklanabilir bağlantılardır. Bir sütun başlığına art arda tıklandığında artan ve azalan sıralama düzeni arasında geçiş yapar.
Çözemediğiniz sorunlarla karşılaşırsanız tamamlanmış uygulamayı indirin.
Dizin sayfasına sıralama ekleme
sıralama parametrelerini içerecek şekilde öğesine dizeler Students/Index.cshtml.cs
PageModel
ekleyin:
public class IndexModel : PageModel
{
private readonly SchoolContext _context;
public IndexModel(SchoolContext context)
{
_context = context;
}
public string NameSort { get; set; }
public string DateSort { get; set; }
public string CurrentFilter { get; set; }
public string CurrentSort { get; set; }
öğesini Students/Index.cshtml.cs
OnGetAsync
aşağıdaki kodla güncelleştirin:
public async Task OnGetAsync(string sortOrder)
{
NameSort = String.IsNullOrEmpty(sortOrder) ? "name_desc" : "";
DateSort = sortOrder == "Date" ? "date_desc" : "Date";
IQueryable<Student> studentIQ = from s in _context.Student
select s;
switch (sortOrder)
{
case "name_desc":
studentIQ = studentIQ.OrderByDescending(s => s.LastName);
break;
case "Date":
studentIQ = studentIQ.OrderBy(s => s.EnrollmentDate);
break;
case "date_desc":
studentIQ = studentIQ.OrderByDescending(s => s.EnrollmentDate);
break;
default:
studentIQ = studentIQ.OrderBy(s => s.LastName);
break;
}
Student = await studentIQ.AsNoTracking().ToListAsync();
}
Yukarıdaki kod, URL'deki sorgu dizesinden bir sortOrder
parametre alır. URL (sorgu dizesi dahil) Bağlayıcı Etiketi Yardımcısı tarafından oluşturulur
sortOrder
Parametre "Ad" veya "Tarih" şeklindedir. Parametresi sortOrder
isteğe bağlı olarak azalan sırayı belirtmek için "_desc" tarafından takip edilir. Varsayılan sıralama düzeni artan düzendedir.
Öğrenciler bağlantısından Dizin sayfası istendiğinde sorgu dizesi yoktur. Öğrenciler soyadına göre artan düzende görüntülenir. Soyadına göre artan düzen, deyimdeki switch
varsayılandır (küçük harf). Kullanıcı bir sütun başlığı bağlantısına tıkladığında, sorgu dizesi değerinde uygun sortOrder
değer sağlanır.
NameSort
ve DateSort
Sayfa tarafından Razor sütun başlığı köprülerini uygun sorgu dizesi değerleriyle yapılandırmak için kullanılır:
public async Task OnGetAsync(string sortOrder)
{
NameSort = String.IsNullOrEmpty(sortOrder) ? "name_desc" : "";
DateSort = sortOrder == "Date" ? "date_desc" : "Date";
IQueryable<Student> studentIQ = from s in _context.Student
select s;
switch (sortOrder)
{
case "name_desc":
studentIQ = studentIQ.OrderByDescending(s => s.LastName);
break;
case "Date":
studentIQ = studentIQ.OrderBy(s => s.EnrollmentDate);
break;
case "date_desc":
studentIQ = studentIQ.OrderByDescending(s => s.EnrollmentDate);
break;
default:
studentIQ = studentIQ.OrderBy(s => s.LastName);
break;
}
Student = await studentIQ.AsNoTracking().ToListAsync();
}
Aşağıdaki kod C# koşullu ?: işlecini içerir:
NameSort = String.IsNullOrEmpty(sortOrder) ? "name_desc" : "";
DateSort = sortOrder == "Date" ? "date_desc" : "Date";
İlk satır null veya boş NameSort
olduğunda sortOrder
"name_desc" olarak ayarlandığını belirtir. Null veya boş değilsesortOrder
, NameSort
boş bir dizeye ayarlanır.
, ?: operator
üçüncül işleç olarak da bilinir.
Bu iki deyim, sayfanın sütun başlığı köprülerini aşağıdaki gibi ayarlamasını sağlar:
Geçerli sıralama düzeni | Soyadı Köprüsü | Tarih Köprüsü |
---|---|---|
Soyadı artan | azalan düzende | ascending |
Soyadı azalan | ascending | ascending |
Artan tarih | ascending | azalan düzende |
Azalan tarih | ascending | ascending |
yöntemi, sıralama ölçütü olarak sütunu belirtmek için LINQ to Entities kullanır. Kod switch deyiminden önce bir IQueryable<Student>
başlatır ve switch deyiminde değiştirir:
public async Task OnGetAsync(string sortOrder)
{
NameSort = String.IsNullOrEmpty(sortOrder) ? "name_desc" : "";
DateSort = sortOrder == "Date" ? "date_desc" : "Date";
IQueryable<Student> studentIQ = from s in _context.Student
select s;
switch (sortOrder)
{
case "name_desc":
studentIQ = studentIQ.OrderByDescending(s => s.LastName);
break;
case "Date":
studentIQ = studentIQ.OrderBy(s => s.EnrollmentDate);
break;
case "date_desc":
studentIQ = studentIQ.OrderByDescending(s => s.EnrollmentDate);
break;
default:
studentIQ = studentIQ.OrderBy(s => s.LastName);
break;
}
Student = await studentIQ.AsNoTracking().ToListAsync();
}
birIQueryable
oluşturulduğunda veya değiştirildiğinde veritabanına hiçbir sorgu gönderilmez. Nesne bir koleksiyona dönüştürülene kadar IQueryable
sorgu yürütülemez. IQueryable
gibi ToListAsync
bir yöntemi çağırarak bir koleksiyona dönüştürülür. Bu nedenle kod, aşağıdaki deyime IQueryable
kadar yürütülmeyen tek bir sorguyla sonuçlanmıştır:
Student = await studentIQ.AsNoTracking().ToListAsync();
OnGetAsync
çok sayıda sıralanabilir sütunla ayrıntılı olabilir.
Öğrenci Dizini sayfasına sütun başlığı köprüleri ekleme
içindeki Students/Index.cshtml
kodu aşağıdaki vurgulanmış kodla değiştirin:
@page
@model ContosoUniversity.Pages.Students.IndexModel
@{
ViewData["Title"] = "Index";
}
<h2>Index</h2>
<p>
<a asp-page="Create">Create New</a>
</p>
<table class="table">
<thead>
<tr>
<th>
<a asp-page="./Index" asp-route-sortOrder="@Model.NameSort">
@Html.DisplayNameFor(model => model.Student[0].LastName)
</a>
</th>
<th>
@Html.DisplayNameFor(model => model.Student[0].FirstMidName)
</th>
<th>
<a asp-page="./Index" asp-route-sortOrder="@Model.DateSort">
@Html.DisplayNameFor(model => model.Student[0].EnrollmentDate)
</a>
</th>
<th></th>
</tr>
</thead>
<tbody>
@foreach (var item in Model.Student)
{
<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-page="./Edit" asp-route-id="@item.ID">Edit</a> |
<a asp-page="./Details" asp-route-id="@item.ID">Details</a> |
<a asp-page="./Delete" asp-route-id="@item.ID">Delete</a>
</td>
</tr>
}
</tbody>
</table>
Yukarıdaki kod:
- ve
EnrollmentDate
sütun başlıklarınaLastName
köprü ekler. - geçerli sıralama düzeni değerleriyle köprüler ayarlamak için ve
DateSort
içindeki bilgileriNameSort
kullanır.
Sıralamanın çalıştığını doğrulamak için:
- Uygulamayı çalıştırın ve Öğrenciler sekmesini seçin.
- Soyadı'ya tıklayın.
- Kayıt Tarihi'ne tıklayın.
Kodu daha iyi anlamak için:
- içinde
Students/Index.cshtml.cs
, üzerindeswitch (sortOrder)
bir kesme noktası ayarlayın. - ve
DateSort
içinNameSort
bir saat ekleyin. - içinde
Students/Index.cshtml
, üzerinde@Html.DisplayNameFor(model => model.Student[0].LastName)
bir kesme noktası ayarlayın.
Hata ayıklayıcıda adım adım ilerleyin.
Öğrenci Dizini sayfasına Arama Kutusu Ekleme
Öğrenci Dizini sayfasına filtreleme eklemek için:
- Sayfaya Razor bir metin kutusu ve gönder düğmesi eklenir. Metin kutusu, ad veya soyadı üzerinde bir arama dizesi sağlar.
- Sayfa modeli, metin kutusu değerini kullanacak şekilde güncelleştirilir.
Index yöntemine filtreleme işlevi ekleme
öğesini Students/Index.cshtml.cs
OnGetAsync
aşağıdaki kodla güncelleştirin:
public async Task OnGetAsync(string sortOrder, string searchString)
{
NameSort = String.IsNullOrEmpty(sortOrder) ? "name_desc" : "";
DateSort = sortOrder == "Date" ? "date_desc" : "Date";
CurrentFilter = searchString;
IQueryable<Student> studentIQ = from s in _context.Student
select s;
if (!String.IsNullOrEmpty(searchString))
{
studentIQ = studentIQ.Where(s => s.LastName.Contains(searchString)
|| s.FirstMidName.Contains(searchString));
}
switch (sortOrder)
{
case "name_desc":
studentIQ = studentIQ.OrderByDescending(s => s.LastName);
break;
case "Date":
studentIQ = studentIQ.OrderBy(s => s.EnrollmentDate);
break;
case "date_desc":
studentIQ = studentIQ.OrderByDescending(s => s.EnrollmentDate);
break;
default:
studentIQ = studentIQ.OrderBy(s => s.LastName);
break;
}
Student = await studentIQ.AsNoTracking().ToListAsync();
}
Yukarıdaki kod:
- parametresini
searchString
yöntemineOnGetAsync
ekler. Arama dizesi değeri, sonraki bölümde eklenen bir metin kutusundan alınır. - LINQ deyimine bir
Where
yan tümcesi eklendi.Where
yan tümcesi yalnızca ad veya soyadı arama dizesini içeren öğrencileri seçer. LINQ deyimi yalnızca aranacak bir değer varsa yürütülür.
Not: Yukarıdaki kod bir IQueryable
nesnede Where
yöntemini çağırır ve filtre sunucuda işlenir. Bazı senaryolarda uygulama, yöntemini bellek içi bir koleksiyonda uzantı yöntemi olarak çağırıyor Where
olabilir. Örneğin, öğesinin bir koleksiyon döndüren IEnumerable
bir depo yöntemine değiştiğini varsayalım_context.Students
.EF CoreDbSet
Sonuç normalde aynı olur ancak bazı durumlarda farklı olabilir.
Örneğin, .NET Framework uygulaması Contains
varsayılan olarak büyük/küçük harfe duyarlı bir karşılaştırma gerçekleştirir. SQL Server'da büyük/küçük harf duyarlılığı, Contains
SQL Server örneğinin harmanlama ayarı tarafından belirlenir. SQL Server varsayılan olarak büyük/küçük harfe duyarlı değildir. ToUpper
testi açıkça büyük/küçük harfe duyarsız hale getirmek için çağrılabilir:
Where(s => s.LastName.ToUpper().Contains(searchString.ToUpper())
Yukarıdaki kod, kod kullanılacak IEnumerable
şekilde değiştirilirse sonuçların büyük/küçük harfe duyarlı olmamasını sağlar. Bir IEnumerable
koleksiyonda çağrıldığında Contains
.NET Core uygulaması kullanılır. Bir IQueryable
nesnede çağrıldığında Contains
veritabanı uygulaması kullanılır. IEnumerable
Bir depodan döndürmenin önemli bir performans cezası olabilir:
- Tüm satırlar DB sunucusundan döndürülür.
- Filtre, uygulamadaki döndürülen tüm satırlara uygulanır.
çağrısı ToUpper
için bir performans cezası vardır. Kod, ToUpper
TSQL SELECT deyiminin WHERE yan tümcesine bir işlev ekler. Eklenen işlev, iyileştiricinin dizin kullanmasını engeller. SQL'in büyük/küçük harfe duyarsız olarak yüklendiği düşünüldüğünde, gerekmediğinde çağrıdan ToUpper
kaçınmak en iyisidir.
Öğrenci Dizini sayfasına Arama Kutusu ekleme
içindePages/Students/Index.cshtml
, bir Arama düğmesi ve çeşitli chrome oluşturmak için aşağıdaki vurgulanmış kodu ekleyin.
@page
@model ContosoUniversity.Pages.Students.IndexModel
@{
ViewData["Title"] = "Index";
}
<h2>Index</h2>
<p>
<a asp-page="Create">Create New</a>
</p>
<form asp-page="./Index" method="get">
<div class="form-actions no-color">
<p>
Find by name:
<input type="text" name="SearchString" value="@Model.CurrentFilter" />
<input type="submit" value="Search" class="btn btn-default" /> |
<a asp-page="./Index">Back to full List</a>
</p>
</div>
</form>
<table class="table">
Yukarıdaki kod, arama metin kutusunu ve düğmesini eklemek için etiket yardımcısını kullanır <form>
. Varsayılan olarak, <form>
etiket yardımcısı form verilerini post ile gönderir. POST ile, parametreler URL'de değil HTTP ileti gövdesinde geçirilir. HTTP GET kullanıldığında, form verileri URL'ye sorgu dizeleri olarak geçirilir. Verileri sorgu dizeleriyle geçirmek, kullanıcıların URL'ye yer işareti eklemesine olanak tanır. W3C yönergeleri, eylem güncelleştirmeyle sonuçlanmadığında GET kullanılmasını önerir.
Uygulamayı test edin:
- Öğrenciler sekmesini seçin ve bir arama dizesi girin.
- Ara'yı seçin.
URL'nin arama dizesini içerdiğine dikkat edin.
http://localhost:5000/Students?SearchString=an
Sayfaya yer işareti eklenirse, yer işareti sayfanın URL'sini ve sorgu dizesini SearchString
içerir. method="get"
etiketindekiform
, sorgu dizesinin oluşturulmasına neden olandır.
Şu anda, bir sütun başlığı sıralama bağlantısı seçildiğinde, Arama kutusundaki filtre değeri kaybolur. Kayıp filtre değeri bir sonraki bölümde düzeltildi.
Öğrenci Dizini sayfasına disk belleği işlevi ekleme
Bu bölümde, disk belleğini desteklemek için bir PaginatedList
sınıf oluşturulur. PaginatedList
sınıfı, tablonun tüm satırlarını almak yerine sunucudaki verileri filtrelemek için ve Take
deyimlerini kullanırSkip
. Aşağıdaki çizimde sayfalama düğmeleri gösterilmektedir.
Proje klasöründe aşağıdaki kodla oluşturun PaginatedList.cs
:
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);
}
}
}
Yukarıdaki CreateAsync
koddaki yöntem sayfa boyutunu ve sayfa numarasını alır ve uygun Skip
ve Take
deyimlerini öğesine IQueryable
uygular. üzerinde IQueryable
çağrıldığındaToListAsync
, yalnızca istenen sayfayı içeren bir Liste döndürür. ve özellikleri HasPreviousPage
HasNextPage
, Önceki ve Sonraki sayfalama düğmelerini etkinleştirmek veya devre dışı bırakmak için kullanılır.
CreateAsync
yöntemi, oluşturmak PaginatedList<T>
için kullanılır. Oluşturucu nesneyi oluşturamaz PaginatedList<T>
, oluşturucular zaman uyumsuz kod çalıştıramaz.
Dizin yöntemine disk belleği işlevi ekleme
içinde Students/Index.cshtml.cs
, öğesinin Student
IList<Student>
türünü olarak PaginatedList<Student>
güncelleştirin:
public PaginatedList<Student> Student { get; set; }
öğesini Students/Index.cshtml.cs
OnGetAsync
aşağıdaki kodla güncelleştirin:
public async Task OnGetAsync(string sortOrder,
string currentFilter, string searchString, int? pageIndex)
{
CurrentSort = sortOrder;
NameSort = String.IsNullOrEmpty(sortOrder) ? "name_desc" : "";
DateSort = sortOrder == "Date" ? "date_desc" : "Date";
if (searchString != null)
{
pageIndex = 1;
}
else
{
searchString = currentFilter;
}
CurrentFilter = searchString;
IQueryable<Student> studentIQ = from s in _context.Student
select s;
if (!String.IsNullOrEmpty(searchString))
{
studentIQ = studentIQ.Where(s => s.LastName.Contains(searchString)
|| s.FirstMidName.Contains(searchString));
}
switch (sortOrder)
{
case "name_desc":
studentIQ = studentIQ.OrderByDescending(s => s.LastName);
break;
case "Date":
studentIQ = studentIQ.OrderBy(s => s.EnrollmentDate);
break;
case "date_desc":
studentIQ = studentIQ.OrderByDescending(s => s.EnrollmentDate);
break;
default:
studentIQ = studentIQ.OrderBy(s => s.LastName);
break;
}
int pageSize = 3;
Student = await PaginatedList<Student>.CreateAsync(
studentIQ.AsNoTracking(), pageIndex ?? 1, pageSize);
}
Yukarıdaki kod, sayfa dizinini, geçerli sortOrder
ve öğesini currentFilter
yöntem imzasına ekler.
public async Task OnGetAsync(string sortOrder,
string currentFilter, string searchString, int? pageIndex)
Aşağıdaki durumlarda tüm parametreler null olur:
- Sayfa, Öğrenciler bağlantısından çağrılır.
- Kullanıcı bir sayfalama veya sıralama bağlantısına tıklamadı.
Sayfalama bağlantısına tıklandığında, sayfa dizini değişkeni görüntülenecek sayfa numarasını içerir.
CurrentSort
Razor Geçerli sıralama düzenini içeren Sayfayı sağlar. Sayfalama sırasında sıralama düzenini korumak için geçerli sıralama düzeninin sayfalama bağlantılarına eklenmesi gerekir.
CurrentFilter
Geçerli filtre dizesini Razor içeren Sayfayı sağlar. Değer CurrentFilter
:
- Disk belleği sırasında filtre ayarlarını korumak için sayfalama bağlantılarına eklenmelidir.
- Sayfa yeniden görüntülendiğinde metin kutusuna geri yüklenmelidir.
Sayfalama sırasında arama dizesi değiştirilirse sayfa 1'e sıfırlanır. Yeni filtre farklı verilerin görüntülenmesine neden olabileceğinden sayfanın 1'e sıfırlanması gerekir. Arama değeri girildiğinde ve Gönder seçildiğinde:
- Arama dizesi değiştirilir.
searchString
Parametresi null değil.
if (searchString != null)
{
pageIndex = 1;
}
else
{
searchString = currentFilter;
}
yöntemi, PaginatedList.CreateAsync
öğrenci sorgusunu disk belleğini destekleyen bir koleksiyon türündeki tek bir öğrenci sayfasına dönüştürür. Tek bir öğrenci sayfası Sayfaya Razor geçirilir.
Student = await PaginatedList<Student>.CreateAsync(
studentIQ.AsNoTracking(), pageIndex ?? 1, pageSize);
içindeki PaginatedList.CreateAsync
iki soru işareti null birleşim işlecini temsil eder. Null birleşim işleci, null atanabilir bir tür için varsayılan değeri tanımlar. İfade (pageIndex ?? 1)
, değeri pageIndex
varsa değerini döndürme anlamına gelir. Değer yoksa pageIndex
1 değerini döndürür.
Öğrenci Razor Sayfasına sayfalama bağlantıları ekleme
içindeki Students/Index.cshtml
işaretlemeyi güncelleştirin. Değişiklikler vurgulanır:
@page
@model ContosoUniversity.Pages.Students.IndexModel
@{
ViewData["Title"] = "Index";
}
<h2>Index</h2>
<p>
<a asp-page="Create">Create New</a>
</p>
<form asp-page="./Index" method="get">
<div class="form-actions no-color">
<p>
Find by name: <input type="text" name="SearchString" value="@Model.CurrentFilter" />
<input type="submit" value="Search" class="btn btn-default" /> |
<a asp-page="./Index">Back to full List</a>
</p>
</div>
</form>
<table class="table">
<thead>
<tr>
<th>
<a asp-page="./Index" asp-route-sortOrder="@Model.NameSort"
asp-route-currentFilter="@Model.CurrentFilter">
@Html.DisplayNameFor(model => model.Student[0].LastName)
</a>
</th>
<th>
@Html.DisplayNameFor(model => model.Student[0].FirstMidName)
</th>
<th>
<a asp-page="./Index" asp-route-sortOrder="@Model.DateSort"
asp-route-currentFilter="@Model.CurrentFilter">
@Html.DisplayNameFor(model => model.Student[0].EnrollmentDate)
</a>
</th>
<th></th>
</tr>
</thead>
<tbody>
@foreach (var item in Model.Student)
{
<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-page="./Edit" asp-route-id="@item.ID">Edit</a> |
<a asp-page="./Details" asp-route-id="@item.ID">Details</a> |
<a asp-page="./Delete" asp-route-id="@item.ID">Delete</a>
</td>
</tr>
}
</tbody>
</table>
@{
var prevDisabled = !Model.Student.HasPreviousPage ? "disabled" : "";
var nextDisabled = !Model.Student.HasNextPage ? "disabled" : "";
}
<a asp-page="./Index"
asp-route-sortOrder="@Model.CurrentSort"
asp-route-pageIndex="@(Model.Student.PageIndex - 1)"
asp-route-currentFilter="@Model.CurrentFilter"
class="btn btn-default @prevDisabled">
Previous
</a>
<a asp-page="./Index"
asp-route-sortOrder="@Model.CurrentSort"
asp-route-pageIndex="@(Model.Student.PageIndex + 1)"
asp-route-currentFilter="@Model.CurrentFilter"
class="btn btn-default @nextDisabled">
Next
</a>
Sütun üst bilgisi bağlantıları, kullanıcının filtre sonuçları içinde sıralama gerçekleştirebilmesi için geçerli arama dizesini yöntemine geçirmek için OnGetAsync
sorgu dizesini kullanır:
<a asp-page="./Index" asp-route-sortOrder="@Model.NameSort"
asp-route-currentFilter="@Model.CurrentFilter">
@Html.DisplayNameFor(model => model.Student[0].LastName)
</a>
Sayfalama düğmeleri etiket yardımcıları tarafından görüntülenir:
<a asp-page="./Index"
asp-route-sortOrder="@Model.CurrentSort"
asp-route-pageIndex="@(Model.Student.PageIndex - 1)"
asp-route-currentFilter="@Model.CurrentFilter"
class="btn btn-default @prevDisabled">
Previous
</a>
<a asp-page="./Index"
asp-route-sortOrder="@Model.CurrentSort"
asp-route-pageIndex="@(Model.Student.PageIndex + 1)"
asp-route-currentFilter="@Model.CurrentFilter"
class="btn btn-default @nextDisabled">
Next
</a>
Uygulamayı çalıştırın ve öğrenciler sayfasına gidin.
- Sayfalamanın çalıştığından emin olmak için farklı sıralama düzenlerindeki sayfalama bağlantılarına tıklayın.
- Sayfalamanın sıralama ve filtreleme ile doğru şekilde çalıştığını doğrulamak için bir arama dizesi girin ve sayfalandırmayı deneyin.
Kodu daha iyi anlamak için:
- içinde
Students/Index.cshtml.cs
, üzerindeswitch (sortOrder)
bir kesme noktası ayarlayın. - , ,
DateSort
CurrentSort
veModel.Student.PageIndex
içinNameSort
bir saat ekleyin. - içinde
Students/Index.cshtml
, üzerinde@Html.DisplayNameFor(model => model.Student[0].LastName)
bir kesme noktası ayarlayın.
Hata ayıklayıcıda adım adım ilerleyin.
Öğrenci istatistiklerini göstermek için Hakkında sayfasını güncelleştirme
Bu adımda, Pages/About.cshtml
her kayıt tarihi için kaç öğrencinin kaydolduysa görüntülenecek şekilde güncelleştirilir. Güncelleştirme gruplandırma kullanır ve aşağıdaki adımları içerir:
- Hakkında Sayfası tarafından kullanılan veriler için bir görünüm modeli oluşturun.
- Görünüm modelini kullanmak için Hakkında sayfasını güncelleştirin.
Görünüm modelini oluşturma
Modeller klasöründe bir SchoolViewModels klasörü oluşturun.
SchoolViewModels klasörüne aşağıdaki kodla bir EnrollmentDateGroup.cs
ekleyin:
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; }
}
}
Hakkında sayfa modelini güncelleştirme
ASP.NET Core 2.2'deki web şablonları Hakkında sayfasını içermez. ASP.NET Core 2.2 kullanıyorsanız Hakkında Razor Sayfasını oluşturun.
Pages/About.cshtml.cs
Dosyayı aşağıdaki kodla güncelleştirin:
using ContosoUniversity.Models.SchoolViewModels;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.EntityFrameworkCore;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using ContosoUniversity.Models;
namespace ContosoUniversity.Pages
{
public class AboutModel : PageModel
{
private readonly SchoolContext _context;
public AboutModel(SchoolContext context)
{
_context = context;
}
public IList<EnrollmentDateGroup> Student { get; set; }
public async Task OnGetAsync()
{
IQueryable<EnrollmentDateGroup> data =
from student in _context.Student
group student by student.EnrollmentDate into dateGroup
select new EnrollmentDateGroup()
{
EnrollmentDate = dateGroup.Key,
StudentCount = dateGroup.Count()
};
Student = await data.AsNoTracking().ToListAsync();
}
}
}
LINQ deyimi, öğrenci varlıklarını kayıt tarihine göre gruplandırır, her gruptaki varlık sayısını hesaplar ve sonuçları bir görünüm modeli nesneleri koleksiyonunda EnrollmentDateGroup
depolar.
Hakkında Razor Sayfasını Değiştirme
Dosyadaki Pages/About.cshtml
kodu aşağıdaki kodla değiştirin:
@page
@model ContosoUniversity.Pages.AboutModel
@{
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.Student)
{
<tr>
<td>
@Html.DisplayFor(modelItem => item.EnrollmentDate)
</td>
<td>
@item.StudentCount
</td>
</tr>
}
</table>
Uygulamayı çalıştırın ve Hakkında sayfasına gidin. Her kayıt tarihi için öğrenci sayısı bir tabloda görüntülenir.
Çözemediğiniz sorunlarla karşılaşırsanız, bu aşama için tamamlanmış uygulamayı indirin.
Ek kaynaklar
Sonraki öğreticide uygulama, veri modelini güncelleştirmek için geçişleri kullanır.
ASP.NET Core
Geri Bildirim
https://aka.ms/ContentUserFeedback.
Çok yakında: 2024 boyunca, içerik için geri bildirim mekanizması olarak GitHub Sorunları’nı kullanımdan kaldıracak ve yeni bir geri bildirim sistemiyle değiştireceğiz. Daha fazla bilgi için bkz.Gönderin ve geri bildirimi görüntüleyin