Öğretici: Sıralama, filtreleme ve sayfalama ekleme - ile MVC'yi ASP.NET EF Core
Önceki öğreticide, Öğrenci varlıkları için temel CRUD işlemleri için bir dizi web sayfası uyguladınız. Bu öğreticide, Öğrenci Dizini sayfasına sıralama, filtreleme ve sayfalama işlevleri ekleyeceksiniz. Ayrıca basit gruplandırmalar da yapacaksınız.
Aşağıdaki çizimde, işiniz bittiğinde sayfanın nasıl görüneceği gösterilmektedir. Sütun başlıkları, kullanıcının bu sütuna göre sıralamak için tıklayabileceği bağlantılardır. Sütun başlığına art arda tıklandığında artan ve azalan sıralama düzeni arasında geçiş yapar.
Bu öğreticide şunları yaptınız:
- Sütun sıralama bağlantıları ekleme
- Arama kutusu ekleme
- Öğrenci Dizinine sayfalama ekleme
- Dizin yöntemine disk belleği ekleme
- Sayfalama bağlantıları ekleme
- Hakkında sayfası oluşturma
Ön koşullar
Sütun sıralama bağlantıları ekleme
Öğrenci Dizini sayfasına sıralama eklemek için Öğrenciler denetleyicisinin Index
yöntemini değiştirip Öğrenci Dizini görünümüne kod ekleyeceksiniz.
Dizin yöntemine sıralama İşlevselliği ekleme
içinde StudentsController.cs
yöntemini aşağıdaki kodla değiştirin Index
:
public async Task<IActionResult> Index(string sortOrder)
{
ViewData["NameSortParm"] = String.IsNullOrEmpty(sortOrder) ? "name_desc" : "";
ViewData["DateSortParm"] = sortOrder == "Date" ? "date_desc" : "Date";
var students = from s in _context.Students
select s;
switch (sortOrder)
{
case "name_desc":
students = students.OrderByDescending(s => s.LastName);
break;
case "Date":
students = students.OrderBy(s => s.EnrollmentDate);
break;
case "date_desc":
students = students.OrderByDescending(s => s.EnrollmentDate);
break;
default:
students = students.OrderBy(s => s.LastName);
break;
}
return View(await students.AsNoTracking().ToListAsync());
}
Bu kod, URL'deki sorgu dizesinden bir sortOrder
parametre alır. Sorgu dizesi değeri, eylem yöntemine parametre olarak ASP.NET Core MVC tarafından sağlanır. parametresi , isteğe bağlı olarak alt çizgi ve azalan sırayı belirtmek için "desc" dizesinin ardından "Name" veya "Date" olan bir dize olacaktır. Varsayılan sıralama düzeni artan düzendedir.
Dizin sayfası ilk kez istenildiğinde sorgu dizesi yoktur. Öğrenciler soyadına göre artan düzende görüntülenir. Bu, deyimdeki switch
fall-through case tarafından belirlenen varsayılan değerdir. Kullanıcı bir sütun başlığı köprüsüne tıkladığında, sorgu dizesinde uygun sortOrder
değer sağlanır.
İki ViewData
öğe (NameSortParm ve DateSortParm), görünüm tarafından sütun başlığı köprülerini uygun sorgu dizesi değerleriyle yapılandırmak için kullanılır.
public async Task<IActionResult> Index(string sortOrder)
{
ViewData["NameSortParm"] = String.IsNullOrEmpty(sortOrder) ? "name_desc" : "";
ViewData["DateSortParm"] = sortOrder == "Date" ? "date_desc" : "Date";
var students = from s in _context.Students
select s;
switch (sortOrder)
{
case "name_desc":
students = students.OrderByDescending(s => s.LastName);
break;
case "Date":
students = students.OrderBy(s => s.EnrollmentDate);
break;
case "date_desc":
students = students.OrderByDescending(s => s.EnrollmentDate);
break;
default:
students = students.OrderBy(s => s.LastName);
break;
}
return View(await students.AsNoTracking().ToListAsync());
}
Bunlar üçüncül deyimlerdir. İlki, parametre null veya boşsa NameSortParm değerinin sortOrder
"name_desc" olarak ayarlanması gerektiğini belirtir; aksi takdirde, boş bir dizeye ayarlanmalıdır. Bu iki deyim, görünümü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
değişken oluşturur, switch deyiminde değiştirir ve deyiminden ToListAsync
switch
sonra yöntemini çağırır. Değişkenleri oluşturduğunuzda ve değiştirdiğinizde IQueryable
veritabanına hiçbir sorgu gönderilmez. Gibi bir yöntemi ToListAsync
çağırarak nesneyi bir koleksiyona dönüştürene IQueryable
kadar sorgu yürütülemez. Bu nedenle, bu kod deyimine kadar yürütülmeyen tek bir sorguyla sonuçlanmıştır return View
.
Bu kod çok sayıda sütunla ayrıntılı olabilir. Bu serideki son öğreticide, sütunun adını bir dize değişkenine geçirmenize olanak tanıyan kodun OrderBy
nasıl yazıldığını gösterilmektedir.
Öğrenci Dizini görünümüne sütun başlığı köprüleri ekleme
içindeki kodu Views/Students/Index.cshtml
, sütun başlığı köprüleri eklemek için aşağıdaki kodla değiştirin. Değiştirilen satırlar vurgulanır.
@model IEnumerable<ContosoUniversity.Models.Student>
@{
ViewData["Title"] = "Index";
}
<h2>Index</h2>
<p>
<a asp-action="Create">Create New</a>
</p>
<table class="table">
<thead>
<tr>
<th>
<a asp-action="Index" asp-route-sortOrder="@ViewData["NameSortParm"]">@Html.DisplayNameFor(model => model.LastName)</a>
</th>
<th>
@Html.DisplayNameFor(model => model.FirstMidName)
</th>
<th>
<a asp-action="Index" asp-route-sortOrder="@ViewData["DateSortParm"]">@Html.DisplayNameFor(model => model.EnrollmentDate)</a>
</th>
<th></th>
</tr>
</thead>
<tbody>
@foreach (var item in Model) {
<tr>
<td>
@Html.DisplayFor(modelItem => item.LastName)
</td>
<td>
@Html.DisplayFor(modelItem => item.FirstMidName)
</td>
<td>
@Html.DisplayFor(modelItem => item.EnrollmentDate)
</td>
<td>
<a asp-action="Edit" asp-route-id="@item.ID">Edit</a> |
<a asp-action="Details" asp-route-id="@item.ID">Details</a> |
<a asp-action="Delete" asp-route-id="@item.ID">Delete</a>
</td>
</tr>
}
</tbody>
</table>
Bu kod, uygun sorgu dizesi değerlerine sahip köprüler ayarlamak için özelliklerdeki ViewData
bilgileri kullanır.
Uygulamayı çalıştırın, Öğrenciler sekmesini seçin ve sıralamanın çalıştığını doğrulamak için Soyadı ve Kayıt Tarihi sütun başlıklarına tıklayın.
Arama kutusu ekleme
Öğrenci Dizini sayfasına filtreleme eklemek için, görünüme bir metin kutusu ve gönder düğmesi ekleyip yönteminde Index
ilgili değişiklikleri yapacaksınız. Metin kutusu, ad ve soyadı alanlarında aranacak bir dize girmenize olanak verir.
Index yöntemine filtreleme işlevi ekleme
içinde StudentsController.cs
yöntemini aşağıdaki kodla değiştirin Index
(değişiklikler vurgulanır).
public async Task<IActionResult> Index(string sortOrder, string searchString)
{
ViewData["NameSortParm"] = String.IsNullOrEmpty(sortOrder) ? "name_desc" : "";
ViewData["DateSortParm"] = sortOrder == "Date" ? "date_desc" : "Date";
ViewData["CurrentFilter"] = searchString;
var students = from s in _context.Students
select s;
if (!String.IsNullOrEmpty(searchString))
{
students = students.Where(s => s.LastName.Contains(searchString)
|| s.FirstMidName.Contains(searchString));
}
switch (sortOrder)
{
case "name_desc":
students = students.OrderByDescending(s => s.LastName);
break;
case "Date":
students = students.OrderBy(s => s.EnrollmentDate);
break;
case "date_desc":
students = students.OrderByDescending(s => s.EnrollmentDate);
break;
default:
students = students.OrderBy(s => s.LastName);
break;
}
return View(await students.AsNoTracking().ToListAsync());
}
yöntemine bir searchString
parametre eklediniz Index
. Arama dizesi değeri, Dizin görünümüne ekleyeceğiniz bir metin kutusundan alınır. AYRıCA LINQ deyimine, yalnızca ad veya soyadı arama dizesini içeren öğrencileri seçen bir where yan tümcesi eklediniz. where yan tümcesini ekleyen deyim yalnızca aranacak bir değer varsa yürütülür.
Dekont
Burada bir IQueryable
nesnede Where
yöntemini çağırırsınız ve filtre sunucuda işlenir. Bazı senaryolarda yöntemini bellek içi bir koleksiyonda uzantı yöntemi olarak çağırabilirsiniz Where
. (Örneğin, EF yerine koleksiyon döndüren IEnumerable
bir DbSet
depo yöntemine başvurması için _context.Students
başvuruyu olarak değiştirdiğinizden bahsedin.) Sonuç normalde aynı olur ancak bazı durumlarda farklı olabilir.
Örneğin, yönteminin Contains
.NET Framework uygulaması varsayılan olarak büyük/küçük harfe duyarlı bir karşılaştırma gerçekleştirir, ancak SQL Server'da bu, SQL Server örneğinin harmanlama ayarı tarafından belirlenir. Bu ayar varsayılan olarak büyük/küçük harfe duyarlı değildir. Testi açıkça büyük/küçük harfe duyarsız hale getirmek için yöntemini çağırabilirsiniz ToUpper
: Where(s => s.LastName.ToUpper(). Contains(searchString.ToUpper()). Bu, kodu daha sonra nesne yerine koleksiyon döndüren IEnumerable
bir depo kullanacak şekilde değiştirirseniz sonuçların IQueryable
aynı kalmasını sağlar. (Bir IEnumerable
koleksiyonda Contains
yöntemini çağırdığınızda .NET Framework uygulamasını alırsınız; bir IQueryable
nesnede çağırdığınızda veritabanı sağlayıcısı uygulamasını alırsınız.) Ancak, bu çözüm için bir performans cezası vardır. Kod, ToUpper
TSQL SELECT deyiminin WHERE yan tümcesine bir işlev koyar. Bu, iyileştiricinin bir dizin kullanmasını engeller. SQL'in büyük/küçük harfe duyarsız olarak yüklendiği göz önünde bulundurulduğunda, büyük/küçük harfe duyarlı bir veri deposuna geçirilene kadar koddan kaçınmak ToUpper
en iyisidir.
Öğrenci Dizini Görünümüne Arama Kutusu Ekleme
içindeViews/Student/Index.cshtml
, başlık, metin kutusu ve Ara düğmesi oluşturmak için tablo etiketini açmadan hemen önce vurgulanan kodu ekleyin.
<p>
<a asp-action="Create">Create New</a>
</p>
<form asp-action="Index" method="get">
<div class="form-actions no-color">
<p>
Find by name: <input type="text" name="SearchString" value="@ViewData["CurrentFilter"]" />
<input type="submit" value="Search" class="btn btn-default" /> |
<a asp-action="Index">Back to Full List</a>
</p>
</div>
</form>
<table class="table">
Bu kod, <form>
arama metin kutusunu ve düğmesini eklemek için etiket yardımcısını kullanır. Varsayılan olarak, <form>
etiket yardımcısı form verilerini POST ile gönderir; bu da parametrelerin URL'de sorgu dizesi olarak değil HTTP ileti gövdesine geçirildiği anlamına gelir. HTTP GET belirttiğinizde, form verileri URL'ye sorgu dizeleri olarak geçirilir ve bu da kullanıcıların URL'ye yer işareti eklemesini sağlar. W3C yönergeleri, eylem güncelleştirmeyle sonuçlanmadığında GET kullanmanızı önerir.
Uygulamayı çalıştırın, Öğrenciler sekmesini seçin, bir arama dizesi girin ve filtrelemenin çalıştığını doğrulamak için Ara'ya tıklayın.
URL'nin arama dizesini içerdiğine dikkat edin.
http://localhost:5813/Students?SearchString=an
Bu sayfaya yer işareti eklerseniz, yer işaretini kullandığınızda filtrelenmiş listeyi alırsınız. Sorgu dizesinin oluşturulmasına form
neden olan etikete ekleme method="get"
işlemidir.
Bu aşamada, bir sütun başlığı sıralama bağlantısına tıklarsanız, Arama kutusuna girdiğiniz filtre değerini kaybedersiniz. Bunu sonraki bölümde düzelteceksiniz.
Öğrenci Dizinine sayfalama ekleme
Öğrenci Dizini sayfasına sayfalama eklemek için, her zaman tablonun tüm satırlarını almak yerine sunucudaki verileri filtrelemek için ve Take
deyimlerini kullanan Skip
bir PaginatedList
sınıf oluşturacaksınız. Ardından yönteminde Index
ek değişiklikler yapacak ve görünüme Index
sayfalama düğmeleri ekleyeceksiniz. Aşağıdaki çizimde sayfalama düğmeleri gösterilmektedir.
Proje klasöründe oluşturun PaginatedList.cs
ve şablon kodunu aşağıdaki kodla değiştirin.
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);
}
}
}
CreateAsync
Bu 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ılabilir.
CreateAsync
Oluşturucular zaman uyumsuz kodu çalıştıramadığından, nesneyi oluşturmak PaginatedList<T>
için oluşturucu yerine bir yöntem kullanılır.
Dizin yöntemine disk belleği ekleme
içinde StudentsController.cs
yöntemini aşağıdaki kodla değiştirin Index
.
public async Task<IActionResult> Index(
string sortOrder,
string currentFilter,
string searchString,
int? pageNumber)
{
ViewData["CurrentSort"] = sortOrder;
ViewData["NameSortParm"] = String.IsNullOrEmpty(sortOrder) ? "name_desc" : "";
ViewData["DateSortParm"] = sortOrder == "Date" ? "date_desc" : "Date";
if (searchString != null)
{
pageNumber = 1;
}
else
{
searchString = currentFilter;
}
ViewData["CurrentFilter"] = searchString;
var students = from s in _context.Students
select s;
if (!String.IsNullOrEmpty(searchString))
{
students = students.Where(s => s.LastName.Contains(searchString)
|| s.FirstMidName.Contains(searchString));
}
switch (sortOrder)
{
case "name_desc":
students = students.OrderByDescending(s => s.LastName);
break;
case "Date":
students = students.OrderBy(s => s.EnrollmentDate);
break;
case "date_desc":
students = students.OrderByDescending(s => s.EnrollmentDate);
break;
default:
students = students.OrderBy(s => s.LastName);
break;
}
int pageSize = 3;
return View(await PaginatedList<Student>.CreateAsync(students.AsNoTracking(), pageNumber ?? 1, pageSize));
}
Bu kod yöntem imzasına bir sayfa numarası parametresi, geçerli bir sıralama düzeni parametresi ve geçerli bir filtre parametresi ekler.
public async Task<IActionResult> Index(
string sortOrder,
string currentFilter,
string searchString,
int? pageNumber)
Sayfa ilk kez görüntülendiğinde veya kullanıcı bir sayfalama veya sıralama bağlantısına tıklamadıysa, tüm parametreler null olur. Sayfalama bağlantısına tıklanırsa, sayfa değişkeni görüntülenecek sayfa numarasını içerir.
ViewData
CurrentSort adlı öğe, sayfalama sırasında sıralama düzeninin aynı tutulması için sayfalama bağlantılarına eklenmesi gerektiğinden geçerli sıralama düzenini içeren görünümü sağlar.
ViewData
CurrentFilter adlı öğe, geçerli filtre dizesini içeren görünümü sağlar. Sayfalama sırasında filtre ayarlarını korumak için bu değerin sayfalama bağlantılarına eklenmesi ve sayfa yeniden görüntülendiğinde metin kutusuna geri yüklenmesi gerekir.
Sayfalama sırasında arama dizesi değiştirilirse, yeni filtre farklı verilerin görüntülenmesine neden olabileceğinden sayfanın 1'e sıfırlanması gerekir. Metin kutusuna bir değer girildiğinde ve Gönder düğmesine basıldığında arama dizesi değiştirilir. Bu durumda parametresi searchString
null değildir.
if (searchString != null)
{
pageNumber = 1;
}
else
{
searchString = currentFilter;
}
Yöntemin Index
sonunda 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. Tek bir öğrenci sayfası görünüme geçirilir.
return View(await PaginatedList<Student>.CreateAsync(students.AsNoTracking(), pageNumber ?? 1, pageSize));
PaginatedList.CreateAsync
yöntemi bir sayfa numarası alır. İki 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; ifadesi (pageNumber ?? 1)
, değeri varsa değerini pageNumber
döndürme veya null ise pageNumber
1 döndürme anlamına gelir.
Sayfalama bağlantıları ekleme
içinde Views/Students/Index.cshtml
, mevcut kodu aşağıdaki kodla değiştirin. Değişiklikler vurgulanır.
@model PaginatedList<ContosoUniversity.Models.Student>
@{
ViewData["Title"] = "Index";
}
<h2>Index</h2>
<p>
<a asp-action="Create">Create New</a>
</p>
<form asp-action="Index" method="get">
<div class="form-actions no-color">
<p>
Find by name: <input type="text" name="SearchString" value="@ViewData["CurrentFilter"]" />
<input type="submit" value="Search" class="btn btn-default" /> |
<a asp-action="Index">Back to Full List</a>
</p>
</div>
</form>
<table class="table">
<thead>
<tr>
<th>
<a asp-action="Index" asp-route-sortOrder="@ViewData["NameSortParm"]" asp-route-currentFilter="@ViewData["CurrentFilter"]">Last Name</a>
</th>
<th>
First Name
</th>
<th>
<a asp-action="Index" asp-route-sortOrder="@ViewData["DateSortParm"]" asp-route-currentFilter="@ViewData["CurrentFilter"]">Enrollment Date</a>
</th>
<th></th>
</tr>
</thead>
<tbody>
@foreach (var item in Model)
{
<tr>
<td>
@Html.DisplayFor(modelItem => item.LastName)
</td>
<td>
@Html.DisplayFor(modelItem => item.FirstMidName)
</td>
<td>
@Html.DisplayFor(modelItem => item.EnrollmentDate)
</td>
<td>
<a asp-action="Edit" asp-route-id="@item.ID">Edit</a> |
<a asp-action="Details" asp-route-id="@item.ID">Details</a> |
<a asp-action="Delete" asp-route-id="@item.ID">Delete</a>
</td>
</tr>
}
</tbody>
</table>
@{
var prevDisabled = !Model.HasPreviousPage ? "disabled" : "";
var nextDisabled = !Model.HasNextPage ? "disabled" : "";
}
<a asp-action="Index"
asp-route-sortOrder="@ViewData["CurrentSort"]"
asp-route-pageNumber="@(Model.PageIndex - 1)"
asp-route-currentFilter="@ViewData["CurrentFilter"]"
class="btn btn-default @prevDisabled">
Previous
</a>
<a asp-action="Index"
asp-route-sortOrder="@ViewData["CurrentSort"]"
asp-route-pageNumber="@(Model.PageIndex + 1)"
asp-route-currentFilter="@ViewData["CurrentFilter"]"
class="btn btn-default @nextDisabled">
Next
</a>
Sayfanın @model
en üstündeki deyimi, görünümün artık nesne yerine List<T>
nesne PaginatedList<T>
aldığını belirtir.
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 denetleyiciye geçirmek için sorgu dizesini kullanır:
<a asp-action="Index" asp-route-sortOrder="@ViewData["DateSortParm"]" asp-route-currentFilter ="@ViewData["CurrentFilter"]">Enrollment Date</a>
Sayfalama düğmeleri etiket yardımcıları tarafından görüntülenir:
<a asp-action="Index"
asp-route-sortOrder="@ViewData["CurrentSort"]"
asp-route-pageNumber="@(Model.PageIndex - 1)"
asp-route-currentFilter="@ViewData["CurrentFilter"]"
class="btn btn-default @prevDisabled">
Previous
</a>
Uygulamayı çalıştırın ve Öğrenciler sayfasına gidin.
Disk belleğinin çalıştığından emin olmak için farklı sıralama düzenlerindeki sayfalama bağlantılarına tıklayın. Ardından bir arama dizesi girin ve disk belleğinin sıralama ve filtreleme ile de düzgün çalıştığını doğrulamak için yeniden sayfalama yapmayı deneyin.
Hakkında sayfası oluşturma
Contoso Üniversitesi web sitesinin Hakkında sayfasında, her kayıt tarihi için kaç öğrencinin kaydoldu olduğunu görüntülersiniz. Bunun için gruplar üzerinde gruplandırma ve basit hesaplamalar gerekir. Bunu başarmak için aşağıdakileri yapacaksınız:
- Görünüme geçirmeniz gereken veriler için bir görünüm modeli sınıfı oluşturun.
- Denetleyicide Home About yöntemini oluşturun.
- Hakkında görünümünü oluşturun.
Görünüm modelini oluşturma
Modeller klasöründe bir SchoolViewModels klasörü oluşturun.
Yeni klasörde bir sınıf dosyası EnrollmentDateGroup.cs
ekleyin ve şablon kodunu aşağıdaki kodla değiştirin:
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; }
}
}
Denetleyiciyi Home Değiştirme
içinde HomeController.cs
dosyasının en üstüne aşağıdaki using deyimlerini ekleyin:
using Microsoft.EntityFrameworkCore;
using ContosoUniversity.Data;
using ContosoUniversity.Models.SchoolViewModels;
using Microsoft.Extensions.Logging;
Sınıf için küme ayracı açıldıktan hemen sonra veritabanı bağlamı için bir sınıf değişkeni ekleyin ve ASP.NET Core DI'den bağlamın bir örneğini alın:
public class HomeController : Controller
{
private readonly ILogger<HomeController> _logger;
private readonly SchoolContext _context;
public HomeController(ILogger<HomeController> logger, SchoolContext context)
{
_logger = logger;
_context = context;
}
Aşağıdaki koda sahip bir About
yöntem ekleyin:
public async Task<ActionResult> About()
{
IQueryable<EnrollmentDateGroup> data =
from student in _context.Students
group student by student.EnrollmentDate into dateGroup
select new EnrollmentDateGroup()
{
EnrollmentDate = dateGroup.Key,
StudentCount = dateGroup.Count()
};
return View(await data.AsNoTracking().ToListAsync());
}
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 Görünümü Oluşturma
Aşağıdaki koda sahip bir Views/Home/About.cshtml
dosya ekleyin:
@model IEnumerable<ContosoUniversity.Models.SchoolViewModels.EnrollmentDateGroup>
@{
ViewData["Title"] = "Student Body Statistics";
}
<h2>Student Body Statistics</h2>
<table>
<tr>
<th>
Enrollment Date
</th>
<th>
Students
</th>
</tr>
@foreach (var item in Model)
{
<tr>
<td>
@Html.DisplayFor(modelItem => item.EnrollmentDate)
</td>
<td>
@item.StudentCount
</td>
</tr>
}
</table>
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.
Kodu alma
Tamamlanan uygulamayı indirin veya görüntüleyin.
Sonraki adımlar
Bu öğreticide şunları yaptınız:
- Sütun sıralama bağlantıları eklendi
- Arama kutusu eklendi
- Öğrenci Dizinine disk belleği eklendi
- Dizin yöntemine disk belleği eklendi
- Sayfalama bağlantıları eklendi
- Hakkında sayfası oluşturuldu
Geçişleri kullanarak veri modeli değişikliklerini işlemeyi öğrenmek için sonraki öğreticiye ilerleyin.
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