bölüm 3, Razor ASP.NET Core sıralama, filtreleme, sayfalama EF Core olan sayfalar
Tom Dykstra, Jeremy Liklikve Jon P Smith tarafından
Contoso Üniversitesi web uygulaması, Razor EF Core ve Visual Studio kullanarak nasıl sayfa Web uygulamaları oluşturacağınızı gösterir. Öğretici serisi hakkında daha fazla bilgi için ilk öğreticiyebakın.
Çözemediğiniz sorunlarla karşılaşırsanız, Tamamlanmış uygulamayı indirin ve öğreticiyi izleyerek bu kodu oluşturduğunuz şekilde karşılaştırın.
Bu öğretici, öğrenciler sayfalarına sıralama, filtreleme ve sayfalama işlevselliği ekler.
Aşağıdaki çizimde tamamlanmış bir sayfa gösterilmektedir. Sütun başlıkları sütunu sıralamak için tıklatılabilir bağlantılardır. Artan ve azalan sıralama düzeni arasında geçiş yapmak için bir sütun başlığına tekrar tekrar tıklayın.

Sıralama Ekle
Pages/öğrenciler/Index. cshtml. cs içindeki kodu, sıralama eklemek için 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:
- Ekleme gerektirir
using System;. - Sıralama parametrelerini içeren özellikleri ekler.
StudentÖzelliğin adını olarak değiştirirStudents.- Yöntemindeki kodu değiştirir
OnGetAsync.
OnGetAsyncYöntemi, sortOrder URL 'deki sorgu dizesinden bir parametre alır. URL ve sorgu dizesi, tutturucu etiketi Yardımcısıtarafından oluşturulur.
sortOrderParametresi ya da olur Name Date . sortOrderParametresi, isteğe bağlı olarak _desc azalan sıra belirtmek için tarafından izlenir. Varsayılan sıralama düzeni artan.
Öğrenciler bağlantısından Dizin sayfası istendiğinde sorgu dizesi yoktur. Öğrenciler, son ada göre artan sırada görüntülenir. Son ada göre artan sıralama, default switch deyimdir. Kullanıcı bir sütun başlığı bağlantısına tıkladığında, sortOrder sorgu dizesi değerinde uygun değer sağlanır.
NameSort ve DateSort 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?:. ?:İşleci üçlü bir işleçtir, üç işlenen alır. İlk satır, sortOrder null veya boş olduğunu belirtir, NameSort olarak ayarlanır name_desc . sortOrderNull veya boş değilse NameSort boş bir dize olarak ayarlanır.
Bu iki deyim, sayfanın sütun başlığı köprülerini şu şekilde ayarlamanızı sağlar:
| Geçerli sıralama düzeni | Son ad Köprüsü | Tarih Köprüsü |
|---|---|---|
| Artan son ad | descending | ascending |
| Azalan son ad | ascending | ascending |
| Artan Tarih | ascending | descending |
| Azalan Tarih | ascending | ascending |
yöntemi, sıralama yapılacak sütunu belirtmek için LINQ to Entities kullanır. Kod, IQueryable<Student> Switch ifadesinden önce bir başlatır ve Switch ifadesinde onu 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. IQueryableNesne bir koleksiyona dönüştürülene kadar sorgu yürütülmez. IQueryable , gibi bir yöntemi çağırarak bir koleksiyona dönüştürülür ToListAsync . Bu nedenle, IQueryable kod, aşağıdaki deyime kadar yürütülemeyen tek bir sorgu ile sonuçlanır:
Students = await studentsIQ.AsNoTracking().ToListAsync();
OnGetAsync çok sayıda sıralanabilir sütunla ayrıntı alabilir. Bu işlevi kodun alternatif bir yolu hakkında daha fazla bilgi için, bu öğretici serisinin MVC sürümünde kodu basitleştirmek için dınamık LINQ kullanma konusuna bakın.
Öğrenci dizini sayfasına sütun başlığı köprüleri ekleme
Öğrenciler/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>
<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:
LastNameVe sütun başlıklarına köprüler eklerEnrollmentDate.- , Ve içindeki bilgileri
NameSortkullanarakDateSortgeçerli sıralama düzeni değerleriyle köprüler ayarlar. - Sayfa başlığını dizinden öğrencilerle değiştirir.
- Üzerinde yapılan değişiklikler
Model.StudentModel.Students.
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.
Filtre ekleme
Öğrenciler dizin sayfasına filtre eklemek için:
- Sayfaya bir metin kutusu ve bir Gönder düğmesi eklenir Razor . 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
Öğrenciler/Index. cshtml. cs dosyasındaki kodu, filtreleme eklemek için 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:
searchStringYöntemine parametresini eklerOnGetAsyncve parametre değeriniCurrentFilterözelliğine kaydeder. Arama dizesi değeri bir sonraki bölüme eklenen bir metin kutusundan alınır.- LINQ deyimi a
Whereyan tümcesine ekler.WhereYan tümce yalnızca adı veya soyadı arama dizesini içeren öğrencileri seçer. LINQ deyimleri yalnızca aranacak bir değer varsa yürütülür.
IQueryable vs. IEnumerable
Kod, Where yöntemi bir nesne üzerinde çağırır IQueryable ve filtre sunucuda işlenir. Bazı senaryolarda, uygulama Where bir bellek içi koleksiyonda bir genişletme yöntemi olarak yöntemi çağırıyor olabilir. Örneğin, _context.Students EF Core 'den DbSet bir koleksiyonu döndüren bir depo yöntemine yapılan değişiklikleri varsayın IEnumerable . Sonuç normalde aynı olur, ancak bazı durumlarda farklı olabilir.
örneğin, uygulamasının .NET Framework uygulanması Contains varsayılan olarak büyük/küçük harfe duyarlı bir karşılaştırma gerçekleştirir. SQL Server, Contains büyük/küçük harf duyarlılığı SQL Server örneğinin harmanlama ayarına göre belirlenir. SQL Server varsayılan olarak büyük/küçük harfe duyarlı değildir. SQLite, büyük/küçük harfe duyarlı olur. ToUpper testi açık 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, Where yöntemin bir veya bir SQLite üzerinde çağrılması durumunda bile filtrenin büyük/küçük harf duyarsız olmasını güvence altına IEnumerable alır.
ContainsBir koleksiyon üzerinde çağrıldığında IEnumerable .NET Core uygulamasını kullanır. ContainsBir nesne üzerinde çağrıldığında IQueryable , veritabanı uygulamasını kullanır.
ContainsBir üzerinde çağırmak IQueryable , genellikle performans nedenleriyle tercih edilir. İle IQueryable , filtreleme veritabanı sunucusu tarafından yapılır. Önce bir IEnumerable oluşturulduysa, tüm satırların veritabanı sunucusundan döndürülmesi gerekir.
Çağırmak için bir performans cezası vardır ToUpper . ToUpperKod, TSQL Select IFADESININ WHERE yan tümcesine bir işlev ekler. Eklenen işlev, iyileştiricinin bir dizin kullanmasını önler. SQL, büyük/küçük harfe duyarsız olarak yüklendiği için, gerekli olmadığında çağrının önüne geçmek en iyisidir ToUpper .
Daha fazla bilgi için bkz. SQLite sağlayıcı ile büyük/küçük harfe duyarsız sorgu kullanma.
Sayfayı Güncelleştir Razor
Pages/Students/Index.cshtml'de kodu değiştirarak bir Ara düğmesi ekleyin.
@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 kodda, <form> arama metin kutusunu ve düğmesini eklemek için etiket yardımcısı ılmaktadır. Varsayılan olarak etiket <form> yardımcısı form verilerini post ile birlikte göndermektedir. POST ile parametreler URL'de değil HTTP ileti gövdesinde geçirildi. HTTP GET kullanılırken, form verileri URL'ye sorgu dizeleri olarak geçiri. Verileri sorgu dizeleriyle geçirme, kullanıcıların URL'ye yer işareti eklemesini sağlar. W3C yönergeleri, eylem bir güncelleştirmeyle sonuçlanmayacaksa GET'in kullanılması önerilir.
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ı kodu kullandıysanız
ToUpperbüyük/büyük/büyük harfe duyarlı değildir.Ara'ya seçin.
URL'nin arama dizesini içerdiğine dikkat edin. Örnek:
https://localhost:5001/Students?SearchString=an
Sayfa yer işaretine eklenirse, yer işareti sayfanın URL'sini ve sorgu SearchString dizesini içerir. method="get"Etiketteki form , sorgu dizesinin oluşturularak oluşturulan değerdir.
Şu anda bir sütun başlığı sıralama bağlantısı seçildiğinde Arama kutusundan filtre değeri kaybolur. Kayıp filtre değeri sonraki bölümde düzeltilmiştir.
Sayfalama ekleme
Bu bölümde, PaginatedList sayfalamayı desteklemek için bir sınıf oluşturulur. PaginatedListsınıfı, Skip Take tablonun tüm satırlarını almak yerine sunucudaki verileri filtrelemek için ve deyimlerini kullanır. Aşağıdaki çizimde sayfalama düğmeleri gösterilmiştir.

PaginatedList sınıfını oluşturma
Proje klasöründe aşağıdaki PaginatedList.cs kodla oluşturun:
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 kodda yer alan yöntemi sayfa boyutunu ve sayfa numarasını alır ve uygun ve Skip Take deyimlerini 'ye IQueryable uygular. üzerinde ToListAsync çağrıldı IQueryable mı, yalnızca istenen sayfayı içeren bir Liste döndürür. ve HasPreviousPage özellikleri, HasNextPage Önceki ve Sonraki disk belleği düğmelerini etkinleştirmek veya devre dışı bırakmak için kullanılır.
CreateAsyncyöntemi, oluşturmak için PaginatedList<T> kullanılır. Oluşturucu nesneyi PaginatedList<T> oluşturamadı; oluşturucular zaman uyumsuz kod çalıştıramadı.
Yapılandırmaya sayfa boyutu ekleme
Yapılandırma PageSize dosyasına appsettings.json ekleyin:
{
"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 sayfalama ekleme
Sayfalama eklemek için Students/Index.cshtml.cs'de 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 türünü
StudentsolarakIList<Student>PaginatedList<Student>değiştirir. - Sayfa dizinini, geçerli
sortOrderve 'icurrentFilteryöntemOnGetAsyncimzasını ekler. - Sıralama sıralamayı özelliğine
CurrentSortkaydeder. - Yeni bir arama dizesi olduğunda sayfa dizinini 1'e sıfırlar.
- Öğrenci
PaginatedListvarlıklarını almak için sınıfını kullanır. - Yapılandırma
pageSizebaşarısız olursa Yapılandırma, 4'te 3 olarak ayarlar.
Aşağıdakiler olduğunda, alan OnGetAsync 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ıklanan sayfa dizini değişkeni, görüntü verilecek sayfa numarasını içerir.
özelliği, CurrentSort Razor Sayfayı geçerli sıralama düzeniyle birlikte sağlar. Sayfalama sırasında sıralama sıralama düzeni tutmak için geçerli sıralama düzeni sayfalama bağlantılarına dahil edilecektir.
özelliği, CurrentFilter Razor Sayfa'ya geçerli filtre dizesini sağlar. CurrentFilterDeğer:
- Sayfalama sırasında filtre ayarlarını korumak için sayfalama bağlantılarına dahil edilecektir.
- Sayfa yeniden oynatıldı olduğunda metin kutusuna geri yüklenecektir.
Sayfalama sırasında arama dizesi değiştirilirse sayfa 1'e sıfırlanır. Yeni filtre farklı verilerin görüntülenmeye neden olması nedeniyle sayfanın 1'e sıfır olması gerekir. Bir arama değeri girilir ve Gönder seçildiğinde:
- Arama dizesi değiştirilir.
- parametresi
searchStringnull değil.
yöntemi, PaginatedList.CreateAsync öğrenci sorgusunu disk belleğini destekleyen bir koleksiyon türünde tek bir öğrenci sayfasına dönüştürür. Bu tek öğrenci sayfası Sayfaya Razor geçirildi.
çağrısında sonrasındaki pageIndex iki soru PaginatedList.CreateAsync işareti, null bir araya çağırma işlecini temsil ediyor. Null-birleştirilebilir bir tür için varsayılan bir değer tanımlar. ifadesi pageIndex ?? 1 değerine pageIndex sahipse değerini döndürür, aksi takdirde 1 değerini döndürür.
Sayfalama bağlantıları ekleme
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>
<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çmek 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ışır olduğundan emin olmak için farklı sıralama sıralarında sayfalama bağlantılarına tıklayın.
- Disk belleğinin sıralama ve filtreleme ile düzgün çalıştığını doğrulamak için bir arama dizesi girin ve disk belleğini deneyin.

Gruplandırma
Bu bölümde, About her kayıt tarihi için kaç öğrencinin kaydolan olduğunu gösteren bir sayfa oluşturur. Güncelleştirme, gruplama kullanır ve aşağıdaki adımları içerir:
- Sayfa tarafından kullanılan veriler için bir görünüm modeli
Aboutoluşturun. - Görünüm
Aboutmodelini kullanmak için sayfayı güncelleştirin.
Görünüm modelini oluşturma
Models/SchoolViewModels klasörü oluşturun.
Aşağıdaki kodla SchoolViewModels/EnrollmentDateGroup.cs oluşturun:
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; }
}
}
Sayfa Razor oluşturma
Aşağıdaki kodla bir Pages/About.cshtml dosyası 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 dosyasını 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 gruplar, her gruptaki varlık sayısını hesaplar ve sonuçları bir görünüm EnrollmentDateGroup modeli nesneleri koleksiyonunda 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, gruplama ve disk belleği işlevleri eklenmiştir.
Aşağıdaki çizimde tamamlanmış bir sayfa gösterilmiştir. Sütun başlıkları, sütunu sıralamak için tıklanabilir bağlantılardır. Bir sütun başlığına tıklarken artan ve azalan sıralama düzeni arasında geçişler olur.

Çöze olmadığınız bir sorunla karşılanırsanız, tamamlanmış uygulamayı indirin.
Dizin sayfasına sıralama ekleme
Sıralama parametrelerini içermesi için Students/Index.cshtml.cs'ye PageModel dize 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; }
Students/Index.cshtml.cs dosyasını 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, sortOrder URL'de sorgu dizesinde bir parametre alır. URL (sorgu dizesi dahil) Sabit Noktası Etiketi Yardımcısı tarafından oluşturulur
parametresi sortOrder "Name" veya "Date" şeklindedir. sortOrderParametre, isteğe bağlı olarak azalan sıra belirtmek için "_DESC" tarafından izlenir. Varsayılan sıralama düzeni artan.
Öğrenciler bağlantısından Dizin sayfası istendiğinde sorgu dizesi yoktur. Öğrenciler, son ada göre artan sırada görüntülenir. Son ada göre artan sıralama, deyimindeki varsayılan (gelen durumdur) switch . Kullanıcı bir sütun başlığı bağlantısına tıkladığında, sortOrder sorgu dizesi değerinde uygun değer sağlanır.
NameSort ve DateSort 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şleciniiçerir:
NameSort = String.IsNullOrEmpty(sortOrder) ? "name_desc" : "";
DateSort = sortOrder == "Date" ? "date_desc" : "Date";
İlk satır, sortOrder null veya boş olduğunu belirtir, NameSort "name_desc" olarak ayarlanır. sortOrderNull veya boş değilse NameSort boş bir dize olarak ayarlanır.
, ?: operator Üçlü işleç olarak da bilinir.
Bu iki deyim, sayfanın sütun başlığı köprülerini şu şekilde ayarlamanızı sağlar:
| Geçerli sıralama düzeni | Son ad Köprüsü | Tarih Köprüsü |
|---|---|---|
| Artan son ad | descending | ascending |
| Azalan son ad | ascending | ascending |
| Artan Tarih | ascending | descending |
| Azalan Tarih | ascending | ascending |
yöntemi, sıralama yapılacak sütunu belirtmek için LINQ to Entities kullanır. Kod, IQueryable<Student> Switch ifadesinden önce bir başlatır ve Switch ifadesinde onu 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();
}
Bir IQueryable oluşturulduğunda veya değiştirildiğinde, veritabanına hiçbir sorgu gönderilmez. IQueryableNesne bir koleksiyona dönüştürülene kadar sorgu yürütülmez. IQueryable , gibi bir yöntemi çağırarak bir koleksiyona dönüştürülür ToListAsync . Bu nedenle, IQueryable kod, aşağıdaki deyime kadar yürütülemeyen tek bir sorgu ile sonuçlanır:
Student = await studentIQ.AsNoTracking().ToListAsync();
OnGetAsync çok sayıda sıralanabilir sütunla ayrıntı alabilir.
Öğrenci dizini sayfasına sütun başlığı köprüleri ekleme
Öğrenciler/Index. cshtml içindeki 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:
LastNameVe sütun başlıklarına köprüler eklerEnrollmentDate.- , Ve içindeki bilgileri
NameSortkullanarakDateSortgeçerli sıralama düzeni değerleriyle köprüler ayarlar.
Sıralamanın çalıştığını doğrulamak için:
- Uygulamayı çalıştırın ve öğrenciler sekmesini seçin.
- Son ad' a tıklayın.
- Kayıt tarihi' ne tıklayın.
Kodu daha iyi anlamak için:
- Öğrenciler/Index. cshtml. cs dosyasında, üzerinde bir kesme noktası ayarlayın
switch (sortOrder). - Ve için bir izleme
NameSortekleyinDateSort. - Öğrenciler/Index. cshtml'de, üzerinde bir kesme noktası ayarlayın
@Html.DisplayNameFor(model => model.Student[0].LastName).
Hata ayıklayıcıda adım adım.
Öğrenciler dizin sayfasına bir arama kutusu ekleyin
Öğrenciler dizin sayfasına filtre eklemek için:
- Sayfaya bir metin kutusu ve bir Gönder düğmesi eklenir Razor . Metin kutusu, ad veya soyadı üzerinde bir arama dizesi sağlar.
- Sayfa modeli metin kutusu değerini kullanacak şekilde güncelleştirilir.
Dizin yöntemine filtreleme işlevi ekleme
Öğrenciler/Index. cshtml. cs ' i 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:
searchStringYöntemine parametresini eklerOnGetAsync. Arama dizesi değeri bir sonraki bölüme eklenen bir metin kutusundan alınır.- LINQ deyimi bir
Whereyan tümcesine eklendi.WhereYan tümce yalnızca adı veya soyadı arama dizesini içeren öğrencileri seçer. LINQ deyimleri yalnızca aranacak bir değer varsa yürütülür.
Note: Yukarıdaki kod, Where metodu bir nesne üzerinde çağırır IQueryable ve filtre sunucuda işlenir. Bazı senaryolarda, uygulama Where bir bellek içi koleksiyonda bir genişletme yöntemi olarak yöntemi çağırıyor olabilir. Örneğin, _context.Students EF Core 'den DbSet bir koleksiyonu döndüren bir depo yöntemine yapılan değişiklikleri varsayın IEnumerable . Sonuç normalde aynı olur, ancak bazı durumlarda farklı olabilir.
örneğin, uygulamasının .NET Framework uygulanması Contains varsayılan olarak büyük/küçük harfe duyarlı bir karşılaştırma gerçekleştirir. SQL Server, Contains büyük/küçük harf duyarlılığı SQL Server örneğinin harmanlama ayarına göre belirlenir. SQL Server varsayılan olarak büyük/küçük harfe duyarlı değildir. ToUpper testi açık 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, kodun kullanım için değişiklik yaptığı durumlarda sonuçların büyük/küçük harf duyarsız olmasını sağlar IEnumerable . ContainsBir koleksiyon üzerinde çağrıldığında IEnumerable .NET Core uygulamasını kullanır. ContainsBir nesne üzerinde çağrıldığında IQueryable , veritabanı uygulamasını kullanır. IEnumerableBir depodan döndürmek önemli bir performans cezasına sahip olabilir:
- Tüm satırlar DB sunucusundan döndürülür.
- Filtre, uygulamadaki tüm döndürülen satırlara uygulanır.
Çağırmak için bir performans cezası vardır ToUpper . ToUpperKod, TSQL Select IFADESININ WHERE yan tümcesine bir işlev ekler. Eklenen işlev, iyileştiricinin bir dizin kullanmasını önler. SQL, büyük/küçük harfe duyarsız olarak yüklendiği için, gerekli olmadığında çağrının önüne geçmek en iyisidir ToUpper .
Öğrenci dizin sayfasına bir arama kutusu ekleyin
Sayfalar/öğrenciler/Index. cshtml' de, bir arama düğmesi ve asi grafik 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, <form> Arama metin kutusu ve düğme eklemek için etiket yardımcısını kullanır. Varsayılan olarak, <form> etiket Yardımcısı form verilerini BIR gönderiyle gönderir. POST ile parametreler, URL 'de değil HTTP ileti gövdesine geçirilir. HTTP GET kullanıldığında, form verileri URL 'ye sorgu dizeleri olarak geçirilir. Verilerin sorgu dizelerine geçirilmesi, kullanıcıların URL 'YI yer işaretine eklemesini sağlar. W3C yönergeleri , eylem bir güncelleştirme ile SONUÇLANMAZSA, Get 'in kullanılması önerilir.
Uygulamayı test etme:
- Öğ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
Sayfa yer işaretiyle, yer işareti sayfanın URL 'sini ve SearchString sorgu dizesini içerir. method="get" form Etiketi, sorgu dizesinin oluşturulmasına neden oldu.
Şu anda, bir sütun başlığı sıralama bağlantısı seçildiğinde, arama kutusundaki filtre değeri kaybedilir. Kayıp filtre değeri bir sonraki bölümde düzeltilir.
Öğrenciler dizin sayfasına sayfalama işlevselliği ekleme
Bu bölümde, PaginatedList sayfalama desteği için bir sınıf oluşturulur. PaginatedListSınıfı, Skip Take tablodaki tüm satırları almak yerine, sunucudaki verileri filtrelemek için ve deyimlerini kullanır. Aşağıdaki çizimde sayfalama düğmeleri gösterilmektedir.

Proje klasöründe aşağıdaki PaginatedList.cs kodla oluşturun:
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
{
get
{
return (PageIndex > 1);
}
}
public bool HasNextPage
{
get
{
return (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 kodda yer alan yöntemi sayfa boyutunu ve sayfa numarasını alır ve uygun ve Skip Take deyimlerini 'ye IQueryable uygular. üzerinde ToListAsync çağrıldı IQueryable mı, yalnızca istenen sayfayı içeren bir Liste döndürür. ve HasPreviousPage özellikleri, HasNextPage Önceki ve Sonraki disk belleği düğmelerini etkinleştirmek veya devre dışı bırakmak için kullanılır.
CreateAsyncyöntemi, oluşturmak için PaginatedList<T> kullanılır. Oluşturucu nesneyi PaginatedList<T> oluşturamadı, oluşturucular zaman uyumsuz kod çalıştıramadı.
Index yöntemine sayfalama işlevi ekleme
Students/Index.cshtml.cs içinde , olan türünü Student olarak IList<Student> PaginatedList<Student> güncelleştirin:
public PaginatedList<Student> Student { get; set; }
Students/Index.cshtml.cs dosyasını 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 'i currentFilter yöntem imzasını ekler.
public async Task OnGetAsync(string sortOrder,
string currentFilter, string searchString, int? pageIndex)
Aşağıdakiler olduğunda 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ıklanan sayfa dizini değişkeni, görüntü verilecek sayfa numarasını içerir.
CurrentSort sayfayı Razor geçerli sıralama düzeniyle birlikte sağlar. Sayfalama sırasında sıralama sıralama düzeni tutmak için geçerli sıralama düzeni sayfalama bağlantılarına dahil edilecektir.
CurrentFilter Geçerli filtre Razor dizesini içeren Sayfayı sağlar. CurrentFilterDeğer:
- Sayfalama sırasında filtre ayarlarını korumak için sayfalama bağlantılarına dahil edilecektir.
- Sayfa yeniden oynatıldı olduğunda metin kutusuna geri yüklenecektir.
Sayfalama sırasında arama dizesi değiştirilirse sayfa 1'e sıfırlanır. Yeni filtre farklı verilerin görüntülenmeye neden olması nedeniyle sayfanın 1'e sıfır olması gerekir. Bir arama değeri girilir ve Gönder seçildiğinde:
- Arama dizesi değiştirilir.
- parametresi
searchStringnull değil.
if (searchString != null)
{
pageIndex = 1;
}
else
{
searchString = currentFilter;
}
yöntemi, PaginatedList.CreateAsync öğrenci sorgusunu disk belleğini destekleyen bir koleksiyon türünde tek bir öğrenci sayfasına dönüştürür. Bu tek öğrenci sayfası Sayfaya Razor geçirildi.
Student = await PaginatedList<Student>.CreateAsync(
studentIQ.AsNoTracking(), pageIndex ?? 1, pageSize);
içinde iki soru işareti PaginatedList.CreateAsync null-coalescing işlecini temsil ediyor. Null-birleştirilebilir bir tür için varsayılan bir değer tanımlar. ifadesi, (pageIndex ?? 1) değerine pageIndex sahipse değerinin dönüş anlamına gelir. pageIndexbir değeri yoksa 1 değerini dönüş.
Öğrenci Sayfasına sayfalama bağlantıları Razor ekleme
Students/Index.cshtml içinde 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ı, geçerli arama dizesini yöntemine iletip kullanıcının filtre sonuçları içinde sıralaması OnGetAsync için 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ışır olduğundan emin olmak için farklı sıralama sıralarında sayfalama bağlantılarına tıklayın.
- Disk belleğinin sıralama ve filtreleme ile düzgün çalıştığını doğrulamak için bir arama dizesi girin ve disk belleğini deneyin.

Kodu daha iyi anlamak için:
- Students/Index.cshtml.cs içinde üzerinde bir kesme noktası
switch (sortOrder)ayarlayın. - , , ve
NameSortiçinDateSortbir saatCurrentSortModel.Student.PageIndexekleyin. - Students/Index.cshtml içinde üzerinde bir kesme noktası
@Html.DisplayNameFor(model => model.Student[0].LastName)ayarlayın.
Hata ayıklayıcıda adım adım inin.
Öğrenci istatistiklerini göstermek için Hakkında sayfasını güncelleştirin
Bu adımda Pages/About.cshtml, her kayıt tarihi için kaç öğrenci kaydolan öğrenci olduğunu görüntülenecek şekilde güncelleştirilir. Güncelleştirme, gruplama 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
Models 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'de web şablonları Hakkında sayfasını içermez. ASP.NET Core 2.2 kullanıyorsanız Hakkında Sayfasını Razor oluşturun.
Pages/About.cshtml.cs dosyasını 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 gruplar, her gruptaki varlık sayısını hesaplar ve sonuçları bir görünüm EnrollmentDateGroup modeli nesneleri koleksiyonunda depolar.
Hakkında Sayfasını Razor Değiştirme
Pages/About.cshtml dosyasındaki 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.
Çöze olmadığınız sorunlar varsa, 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.