Sdílet prostřednictvím


Kurz: Přidání řazení, filtrování a stránkování – ASP.NET MVC pomocí EF Core

V předchozím tutoriálu jste implementovali sadu webových stránek pro základní operace CRUD pro entity studentů. V tomto kurzu přidáte funkce řazení, filtrování a stránkování na stránku Index studentů. Také vytvoříte stránku, která provádí jednoduché seskupení.

Následující obrázek ukazuje, jak bude stránka vypadat po dokončení. Záhlaví sloupců jsou odkazy, na které uživatel může kliknout a seřadit podle tohoto sloupce. Opakovaným kliknutím na záhlaví sloupce se přepíná mezi vzestupným a sestupným pořadím řazení.

Indexová stránka studentů

V tomto kurzu se naučíte:

  • Přidejte odkazy pro řazení sloupců
  • Přidání vyhledávacího pole
  • Přidání stránkování do indexu Studentů
  • Přidání stránkování do metody Index
  • Přidání stránkovacího odkazu
  • Vytvoření stránky O aplikaci

Požadavky

Pokud chcete přidat řazení na stránku Index studenta, změníte Index metodu kontroleru Students a přidáte kód do zobrazení Index studenta.

Přidání funkce řazení do metody indexu

V StudentsController.cspříkazu nahraďte metodu Index následujícím kódem:

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());
}

Tento kód obdrží sortOrder parametr z řetězce dotazu v adrese URL. Hodnotu řetězce dotazu poskytuje ASP.NET Core MVC jako parametr metody akce. Parametr bude řetězec, který je buď "Name" nebo "Date", volitelně následuje podtržítko a řetězec "desc" k určení sestupného pořadí. Výchozí pořadí řazení je vzestupné.

Při prvním vyžádání indexové stránky neexistuje žádný řetězec dotazu. Studenti jsou zobrazeni ve vzestupném pořadí podle příjmení, což je výchozí nastavení, které je zajištěno ve výchozím případě v příkazu switch. Když uživatel klikne na hypertextový odkaz záhlaví sloupce, v řetězci dotazu se zobrazí příslušná sortOrder hodnota.

ViewData Dva prvky (NameSortParm a DateSortParm) se používají v zobrazení ke konfiguraci hypertextových odkazů záhlaví sloupců s příslušnými řetězcovými hodnotami dotazu.

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());
}

Jedná se o ternární příkazy. První určuje, že pokud sortOrder je parametr null nebo prázdný, nameSortParm by měl být nastaven na "name_desc". Jinak by měl být nastaven na prázdný řetězec. Tyto dva příkazy umožňují zobrazení nastavit hypertextové odkazy záhlaví sloupců následujícím způsobem:

Aktuální pořadí řazení Hypertextový odkaz na příjmení Hypertextový odkaz na datum
Příjmení vzestupně sestupný ascending
Příjmení sestupně vzestupný vzestupný
Datum vzestupně vzestupně sestupující
Datum sestupně ascending vzestupný

Metoda používá LINQ to Entities k určení sloupce, podle který se má seřadit. Kód vytvoří proměnnou IQueryable před příkazem switch, upraví ho v příkazu switch a zavolá ToListAsync metodu za příkazem switch . Při vytváření a úpravě IQueryable proměnných se do databáze neposílají žádné dotazy. Dotaz se nespustí, dokud nepřeveďte IQueryable objekt do kolekce voláním metody, jako ToListAsyncje . Výsledkem tohoto kódu je proto jeden dotaz, který se nespustí, dokud se return View příkaz nespustí.

Tento kód by se mohl stát rozvláčným při velkém počtu sloupců. Poslední kurz v této sérii ukazuje, jak napsat kód, který umožňuje předat název OrderBy sloupce v řetězcové proměnné.

Nahraďte kód v Views/Students/Index.cshtml, následujícím kódem pro přidání hypertextových odkazů záhlaví sloupce. Změněné čáry jsou zvýrazněné.

@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>

Tento kód používá informace ve ViewData vlastnostech k nastavení hypertextových odkazů s příslušnými hodnotami řetězce dotazu.

Spusťte aplikaci, vyberte kartu Studenti a kliknutím na záhlaví sloupců Příjmení a Datum registrace ověřte, že řazení funguje.

Indexovací stránka studentů v pořadí názvů

Pokud chcete přidat filtrování na stránku Index studentů, přidáte do zobrazení textové pole a tlačítko odeslat a provedete odpovídající změny v Index metodě. Textové pole umožňuje zadat řetězec k vyhledání v polích jméno a příjmení.

Přidání funkce filtrování do metody Index

V StudentsController.cspříkazu nahraďte metodu Index následujícím kódem (změny jsou zvýrazněny).

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());
}

K metodě Index jste přidali parametr searchString. Hodnota vyhledávacího řetězce se získává z textového pole, které přidáte do Index View. Přidali jste také do příkazu LINQ klauzuli where, která vybere jenom studenty, jejichž křestní jméno nebo příjmení obsahuje hledaný řetězec. Příkaz, který přidá klauzuli where, se provede pouze v případě, že je hodnota, kterou chcete vyhledat.

Poznámka:

Tady voláte metodu WhereIQueryable na objektu a filtr se zpracuje na serveru. V některých scénářích můžete metodu Where volat jako metodu rozšíření v kolekci v paměti. (Předpokládejme například, že změníte odkaz _context.Students tak, že místo odkazování na EF DbSet bude odkazovat na metodu úložiště, která vrací kolekci IEnumerable.) Výsledek by obvykle byl stejný, ale v některých případech se může lišit.

Například implementace metody Contains v rozhraní .NET Framework provádí ve výchozím nastavení porovnání s rozlišováním velkých a malých písmen, ale v SQL Serveru je to určeno kolací instance SQL Serveru. Toto nastavení je ve výchozím stavu nerozlišující malá a velká písmena. Metodu ToUpper můžete volat tak, aby test explicitně nerozlišil malá a velká písmena: Where(s>=s.LastName.ToUpper(). Contains(searchString.Toupper()) To zajistí, aby výsledky zůstaly stejné, pokud později změníte kód tak, aby používal úložiště, které vrací IEnumerable kolekci místo objektu IQueryable . (Při volání Contains metody v IEnumerable kolekci získáte implementaci rozhraní .NET Framework; když ji zavoláte na IQueryable objektu, získáte implementaci zprostředkovatele databáze.) Pro toto řešení je ale snížení výkonu. Kód ToUpper by vložil funkci do klauzule WHERE příkazu TSQL SELECT. Tím by se zabránilo použití indexu optimalizátoru. Vzhledem k tomu, že SQL se většinou instaluje bez rozlišování velkých a malých písmen, je nejlepší se kódu ToUpper vyhnout, dokud nemigrujete do úložiště dat bez rozlišování velkých a malých písmen.

Přidat vyhledávací pole do zobrazení studentského indexu

V Views/Student/Index.cshtml přidejte zvýrazněný kód bezprostředně před počáteční značku tabulky, pokud chcete vytvořit titulek, textové pole a tlačítko Hledat.

<p>
    <a asp-action="Create">Create New</a>
</p>

<form asp-action="Index" method="get">
    <div class="form-actions no-color">
        <p>
            <label>Find by name: <input type="text" name="SearchString" value="@ViewData["CurrentFilter"]" /></label>
            <input type="submit" value="Search" class="btn btn-default" /> |
            <a asp-action="Index">Back to Full List</a>
        </p>
    </div>
</form>

<table class="table">

Tento kód používá <form>pomocník značek k přidání vyhledávacího textového pole a tlačítka. Ve výchozím nastavení <form> pomocník značky odesílá data formuláře pomocí POST, což znamená, že parametry se předávají v textu zprávy HTTP a ne v adrese URL jako dotazovací řetězce. Když zadáte HTTP GET, data formuláře se v adrese URL předávají jako parametry dotazu, což uživatelům umožňuje si adresu URL uložit do záložek. Pokyny W3C doporučují, abyste měli použít get, když akce nemá za následek aktualizaci.

Spusťte aplikaci, vyberte kartu Studenti , zadejte hledaný řetězec a kliknutím na Hledat ověřte, že filtrování funguje.

Indexovací stránka studentů s filtrováním

Všimněte si, že adresa URL obsahuje hledaný řetězec.

http://localhost:5813/Students?SearchString=an

Pokud si tuto stránku označíte záložkou, zobrazí se filtrovaný seznam při použití této záložky. Přidání method="get" ke form značce je to, co způsobilo vygenerování řetězce dotazu.

Pokud v této fázi kliknete na odkaz pro řazení záhlaví sloupce, ztratíte hodnotu filtru, kterou jste zadali do vyhledávacího pole. Opravíte to v další části.

Přidání stránkování do indexu Studentů

Pokud chcete přidat stránkování na stránku Index studentů, vytvoříte PaginatedList třídu, která používá Skip a Take uvádí příkazy k filtrování dat na serveru místo toho, abyste vždy načítá všechny řádky tabulky. Pak provedete další změny v Index metodě a přidáte do zobrazení stránkovací tlačítka Index . Následující obrázek znázorňuje stránkovací tlačítka.

Indexová stránka studentů se stránkovacími odkazy

Ve složce projektu vytvořte PaginatedList.csa pak nahraďte kód šablony následujícím kódem.

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);
        }
    }
}

Metoda CreateAsync v tomto kódu přijímá velikost stránky a číslo stránky a použije příslušné příkazy Skip a Take na IQueryable. Při volání ToListAsync na IQueryable vrátí seznam obsahující pouze požadovanou stránku. Vlastnosti HasPreviousPage a HasNextPage lze použít k povolení nebo zakázání stránkovacího tlačítka předchozí a další.

Metoda CreateAsync se používá místo konstruktoru k vytvoření objektu PaginatedList<T> , protože konstruktory nemohou spustit asynchronní kód.

Přidejte stránkování do metody Index

V StudentsController.cs, nahraďte metodu Index následujícím kódem.

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));
}

Tento kód přidá do podpisu metody parametr čísla stránky, aktuální parametr pořadí řazení a aktuální parametr filtru.

public async Task<IActionResult> Index(
    string sortOrder,
    string currentFilter,
    string searchString,
    int? pageNumber)

Při prvním zobrazení stránky nebo pokud uživatel neklikli na stránkovací nebo seřazovací odkaz, budou mít všechny parametry hodnotu null. Pokud kliknete na stránkovací odkaz, proměnná stránky bude obsahovat číslo stránky, které se má zobrazit.

Element ViewData s názvem CurrentSort poskytuje zobrazení aktuální pořadí řazení, protože toto pořadí musí být součástí stránkovacích odkazů, aby při stránkování zůstalo stejné.

Element ViewData s názvem CurrentFilter poskytuje zobrazení s aktuálním řetězcem filtru. Tato hodnota musí být zahrnuta ve stránkovacích odkazech, aby bylo možné zachovat nastavení filtru během stránkování, a při opětovném zobrazení stránky se musí obnovit do textového pole.

Pokud se během stránkování změní hledaný řetězec, musí se stránka resetovat na hodnotu 1, protože nový filtr může vést k zobrazení různých dat. Hledaný řetězec se změní při zadání hodnoty do textového pole a stisknutí tlačítka Odeslat. V takovém případě searchString parametr nemá hodnotu null.

if (searchString != null)
{
    pageNumber = 1;
}
else
{
    searchString = currentFilter;
}

Na konci metody Index převede metoda PaginatedList.CreateAsync dotaz studenta na jednu stránku se studenty v typu kolekce, která podporuje stránkování. Tato jediná stránka studentů je pak předána na zobrazení.

return View(await PaginatedList<Student>.CreateAsync(students.AsNoTracking(), pageNumber ?? 1, pageSize));

Metoda PaginatedList.CreateAsync přebírá číslo stránky. Dvě otazníky představují tzv. operátor nulového sjednocení. Operátor nulového sjednocení definuje výchozí hodnotu pro typ s možnou hodnotou null; výraz (pageNumber ?? 1) znamená, že vrátí hodnotu pageNumber , pokud má hodnotu, nebo vrátí hodnotu 1, pokud pageNumber má hodnotu null.

Nahraďte Views/Students/Index.cshtmlstávající kód následujícím kódem. Změny jsou zvýrazněné.

@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>
            <label>Find by name: <input type="text" name="SearchString" value="@ViewData["CurrentFilter"]" /></label>
            <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>

Příkaz @model v horní části stránky určuje, že zobrazení nyní získá PaginatedList<T> objekt místo objektu List<T> .

Odkazy v záhlaví sloupce používají řetězec dotazu k předání aktuálního vyhledávacího řetězce řadiči, aby mohl uživatel třídit výsledky filtrování.

<a asp-action="Index" asp-route-sortOrder="@ViewData["DateSortParm"]" asp-route-currentFilter ="@ViewData["CurrentFilter"]">Enrollment Date</a>

Stránkovací tlačítka jsou zobrazována pomocí tag helperů.

<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>

Spusťte aplikaci a přejděte na stránku Studenti.

Indexová stránka studentů se stránkovacími odkazy

Klikněte na stránkovací odkazy v různých pořadích řazení a ujistěte se, že stránkování funguje. Potom zadejte hledaný řetězec a zkuste stránkování zopakovat, abyste ověřili, že stránkování funguje s řazením a filtrováním správně.

Vytvoření stránky O aplikaci

Na stránce Informace o webu Contoso University se zobrazí počet studentů, kteří se zaregistrovali ke každému datu registrace. To vyžaduje seskupování a jednoduché výpočty skupin. Uděláte to takto:

  • Vytvořte třídu modelu zobrazení pro data, která potřebujete předat do zobrazení.
  • Vytvořte v kontroleru metodu Home About.
  • Vytvořte zobrazení O aplikaci.

Vytvoření modelu zobrazení

Ve složce Models vytvořte složku SchoolViewModels.

Do nové složky přidejte soubor EnrollmentDateGroup.cs třídy a nahraďte kód šablony následujícím kódem:

using System;
using System.ComponentModel.DataAnnotations;

namespace ContosoUniversity.Models.SchoolViewModels
{
    public class EnrollmentDateGroup
    {
        [DataType(DataType.Date)]
        public DateTime? EnrollmentDate { get; set; }

        public int StudentCount { get; set; }
    }
}

Home Úprava kontroleru

Do HomeController.cshorní části souboru přidejte následující příkazy using:

using Microsoft.EntityFrameworkCore;
using ContosoUniversity.Data;
using ContosoUniversity.Models.SchoolViewModels;
using Microsoft.Extensions.Logging;

Přidejte proměnnou třídy pro kontext databáze bezprostředně za levou složenou závorku třídy a získejte instanci kontextu z ASP.NET Core DI:

public class HomeController : Controller
{
    private readonly ILogger<HomeController> _logger;
    private readonly SchoolContext _context;

    public HomeController(ILogger<HomeController> logger, SchoolContext context)
    {
        _logger = logger;
        _context = context;
    }

Přidejte metodu About s následujícím kódem:

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());
}

Příkaz LINQ seskupí entity studentů podle data registrace, vypočítá počet entit v každé skupině a uloží výsledky do kolekce EnrollmentDateGroup objektů modelu zobrazení.

Vytvoření zobrazení o aplikaci

Views/Home/About.cshtml Přidejte soubor s následujícím kódem:

@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>

Spusťte aplikaci a přejděte na stránku O aplikaci. Počet studentů pro každé datum registrace se zobrazí v tabulce.

Získání kódu

Stáhněte nebo zobrazte dokončenou aplikaci.

Další kroky

V tomto kurzu se naučíte:

  • Přidání odkazů pro řazení sloupců
  • Přidání vyhledávacího pole
  • Přidání stránkování do indexu Studentů
  • Přidání stránkování do metody Index
  • Přidání stránkovacího odkazu
  • Vytvoření stránky O aplikaci

V dalším kurzu se dozvíte, jak zpracovávat změny datového modelu pomocí migrací.