Poznámka:
Přístup k této stránce vyžaduje autorizaci. Můžete se zkusit přihlásit nebo změnit adresáře.
Přístup k této stránce vyžaduje autorizaci. Můžete zkusit změnit adresáře.
V předchozím kurzu jste vytvořili aplikaci MVC, která ukládá a zobrazuje data pomocí Entity Frameworku (EF) 6 a SQL Server LocalDB. V tomto kurzu zkontrolujete a přizpůsobíte kód vytvoření, čtení, aktualizace, odstranění (CRUD), který vygenerování MVC automaticky vytvoří v řadičích a zobrazeních.
Poznámka:
Běžným postupem je implementovat vzor úložiště, abyste vytvořili abstraktní vrstvu mezi kontrolerem a vrstvou přístupu k datům. Aby byly tyto kurzy jednoduché a zaměřené na výuku samotného EF 6, nepoužívají úložiště. Informace o tom, jak implementovat úložiště, najdete v mapě obsahu ASP.NET Data Accessu.
Tady jsou příklady webových stránek, které vytvoříte:



V tomto kurzu se naučíte:
- Vytvoření stránky Podrobností
- Aktualizace stránky Vytvořit
- Aktualizace metody HttpPost Edit
- Aktualizace stránky Odstranit
- Zavření připojení k databázi
- Zpracování transakcí
Požadavky
Vytvoření stránky Podrobností
Vygenerovaný kód pro stránku Students Index opustil Enrollments vlastnost, protože tato vlastnost obsahuje kolekci. Na Details stránce zobrazíte obsah kolekce v tabulce HTML.
V Controllers\StudentController.cs metoda akce pro Details zobrazení používá metodu Find k načtení jedné Student entity.
public ActionResult Details(int? id)
{
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
Student student = db.Students.Find(id);
if (student == null)
{
return HttpNotFound();
}
return View(student);
}
Hodnota klíče se předá metodě jako id parametr a pochází ze směrovacích dat v hypertextovém odkazu Podrobnosti na stránce Index.
Tip: Směrování dat
Směrovací data jsou data, která pořadač modelů našel v segmentu adresy URL zadaném ve směrovací tabulce. Například výchozí trasa určuje controller, actiona id segmenty:
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
V následující adrese URL se výchozí trasy mapují Instructor jako controllersměrovací hodnoty , Index jako action a 1 jako idhodnoty směrovacích dat.
http://localhost:1230/Instructor/Index/1?courseID=2021
?courseID=2021 je hodnota řetězce dotazu. Pořadač modelů bude fungovat také v případě, že předáte id hodnotu řetězce dotazu:
http://localhost:1230/Instructor/Index?id=1&CourseID=2021
Adresy URL se vytvářejí příkazy ActionLink v zobrazení Razor. V následujícím kódu id se parametr shoduje s výchozí trasou, takže id se přidá do směrovacích dat.
@Html.ActionLink("Select", "Index", new { id = item.PersonID })
V následujícím kódu courseID neodpovídá parametru ve výchozí trase, takže se přidá jako řetězec dotazu.
@Html.ActionLink("Select", "Index", new { courseID = item.CourseID })
Vytvoření stránky Podrobnosti
Otevřete Views\Student\Details.cshtml.
Každé pole se zobrazí pomocí pomocné rutiny
DisplayFor, jak je znázorněno v následujícím příkladu:<dt> @Html.DisplayNameFor(model => model.LastName) </dt> <dd> @Html.DisplayFor(model => model.LastName) </dd>EnrollmentDateZa pole a bezprostředně před uzavírací</dl>značku přidejte zvýrazněný kód, který zobrazí seznam registrací, jak je znázorněno v následujícím příkladu:<dt> @Html.DisplayNameFor(model => model.EnrollmentDate) </dt> <dd> @Html.DisplayFor(model => model.EnrollmentDate) </dd> <dt> @Html.DisplayNameFor(model => model.Enrollments) </dt> <dd> <table class="table"> <tr> <th>Course Title</th> <th>Grade</th> </tr> @foreach (var item in Model.Enrollments) { <tr> <td> @Html.DisplayFor(modelItem => item.Course.Title) </td> <td> @Html.DisplayFor(modelItem => item.Grade) </td> </tr> } </table> </dd> </dl> </div> <p> @Html.ActionLink("Edit", "Edit", new { id = Model.ID }) | @Html.ActionLink("Back to List", "Index") </p>Pokud je odsazení kódu po vložení kódu chybné, stiskněte Ctrl+K, Ctrl+D a naformátujte ho.
Tento kód prochází entitami v
Enrollmentsnavigační vlastnosti. Pro každouEnrollmententitu ve vlastnosti se zobrazí název kurzu a známka. Název kurzu se načte zCourseentity, která je uložená vCoursenavigační vlastnostiEnrollmentsentity. Všechna tato data se z databáze načítají automaticky, když je to potřeba. Jinými slovy, používáte opožděné načítání. Nezadali jste dychtivé načítání proCoursesnavigační vlastnost, takže registrace nebyly načteny ve stejném dotazu, který získal studenty. Místo toho se při prvním pokusuEnrollmentso přístup k navigační vlastnosti odešle do databáze nový dotaz, který načte data. Další informace o opožděné načítání a dychtivé načítání si můžete přečíst v kurzu Čtení souvisejících dat dále v této sérii.Otevřete stránku Podrobnosti spuštěním programu (Ctrl+F5), výběrem karty Studenti a následným kliknutím na odkaz Podrobnosti pro Alexander Carson. (Pokud stisknete Při otevření souboru Details.cshtml se zobrazí ctrl+F5, zobrazí se chyba HTTP 400. Důvodem je to, že se Visual Studio pokusí spustit stránku Podrobností, ale nebyl dosažen z odkazu, který určuje studenta, který se má zobrazit. Pokud k tomu dojde, odeberte z adresy URL položku Student/Details a zkuste to znovu nebo zavřete prohlížeč, klikněte pravým tlačítkem myši na projekt a klikněte na Zobrazit>v prohlížeči.)
Zobrazí se seznam kurzů a známek pro vybraného studenta.
Zavřete prohlížeč.
Aktualizace stránky Vytvořit
V Controllers\StudentController.cs nahraďte metodu HttpPostAttribute
Createakce následujícím kódem. Tento kód přidátry-catchblok a odebere z atributu BindAttribute pro vygenerovanouIDmetodu:[HttpPost] [ValidateAntiForgeryToken] public ActionResult Create([Bind(Include = "LastName, FirstMidName, EnrollmentDate")]Student student) { try { if (ModelState.IsValid) { db.Students.Add(student); db.SaveChanges(); return RedirectToAction("Index"); } } catch (DataException /* dex */) { //Log the error (uncomment dex variable name and add a line here to write a log. ModelState.AddModelError("", "Unable to save changes. Try again, and if the problem persists see your system administrator."); } return View(student); }Tento kód přidá entitu
Studentvytvořenou pořadačem modelu ASP.NET MVC doStudentssady entit a uloží změny do databáze. Pořadač modelů odkazuje na funkci ASP.NET MVC, která usnadňuje práci s daty odeslanými formulářem. Pořadač modelu převede publikované hodnoty formuláře na typy CLR a předá je metodě akce v parametrech. V tomto případě pořadač modelů vytvoříStudentinstanci entity za vás pomocí hodnot vlastností zFormkolekce.Odebrali
IDjste z atributu Bind, protožeIDje hodnota primárního klíče, kterou SQL Server nastaví automaticky při vložení řádku. Vstup od uživatele nenastavíIDhodnotu.Upozornění zabezpečení – Atribut
ValidateAntiForgeryTokenpomáhá předcházet útokům typu útok na negery mezi weby . Vyžaduje odpovídajícíHtml.AntiForgeryToken()příkaz v zobrazení, který uvidíte později.Atribut
Bindje jedním ze způsobů, jak chránit před nadměrným publikováním ve scénářích vytváření. Předpokládejme například, že entitaStudentobsahujeSecretvlastnost, kterou nechcete, aby tato webová stránka byla nastavena.public class Student { public int ID { get; set; } public string LastName { get; set; } public string FirstMidName { get; set; } public DateTime EnrollmentDate { get; set; } public string Secret { get; set; } public virtual ICollection<Enrollment> Enrollments { get; set; } }I když nemáte
Secretpole na webové stránce, mohl by hacker použít nástroj, jako je fiddler, nebo napsat nějaký JavaScript a publikovatSecrethodnotu formuláře. BindAttribute Bez omezení atributů pole, která binder modelu používá při vytvářeníStudentinstance, by pořadač modelu vyzvedá tutoSecrethodnotu formuláře a použil ho k vytvořeníStudentinstance entity. Pak by se ve vaší databázi aktualizovala jakákoli hodnota, kterou hacker zadal proSecretpole formuláře. Následující obrázek znázorňuje nástroj fiddler, který přidáváSecretpole (s hodnotou OverPost) do odeslaných hodnot formuláře.
Hodnota OverPost by se pak úspěšně přidala do
Secretvlastnosti vloženého řádku, i když jste nikdy nechtěli, aby webová stránka mohla tuto vlastnost nastavit.Nejlepší je použít
Includeparametr s atributemBindk explicitní výpisu polí. Parametr je také možné použítExcludek blokování polí, která chcete vyloučit.IncludeDůvodem je bezpečnější, že když do entity přidáte novou vlastnost, nebude nové pole automaticky chráněno seznamemExclude.Pokud chcete zabránit nadměrnému umístění ve scénářích úprav, je nejprve čtením entity z databáze a následným voláním
TryUpdateModela předáním explicitního seznamu povolených vlastností. To je metoda použitá v těchto kurzech.Alternativní způsob, jak zabránit nadměrnému příspěvku, který upřednostňuje mnoho vývojářů, je použít modely zobrazení místo tříd entit s vazbou modelu. Do modelu zobrazení zahrňte pouze vlastnosti, které chcete aktualizovat. Po dokončení pořadače modelu MVC zkopírujte vlastnosti modelu zobrazení do instance entity, volitelně pomocí nástroje, jako je automapper. Použijte databázi. Položka instance entity, která nastaví její stav na Beze změny, a pak vlastnost("PropertyName"). IsModified to true on each entity property that is included in the view model. Tato metoda funguje ve scénářích pro úpravy i vytváření.
Kromě atributu
Bindtry-catchje blok jedinou změnou, kterou jste provedli v kódu vygenerovaného uživatelského rozhraní. Pokud je při ukládání změn zachycena výjimka odvozená od DataException změn, zobrazí se obecná chybová zpráva. DataException Výjimky jsou někdy způsobeny něčím, co není externí aplikací, a ne programovací chybou, takže uživateli doporučujeme zkusit to znovu. I když není v této ukázce implementováno, aplikace v produkční kvalitě zaznamená výjimku. Další informace najdete v části Protokol pro přehled v tématu Monitorování a telemetrie (vytváření reálných cloudových aplikací pomocí Azure).Kód v Views\Student\Create.cshtml je podobný tomu, co jste viděli v Details.cshtml, s tím rozdílem, že
EditorForaValidationMessageForpomocné rutiny se používají pro každé pole místoDisplayFor. Tady je příslušný kód:<div class="form-group"> @Html.LabelFor(model => model.LastName, new { @class = "control-label col-md-2" }) <div class="col-md-10"> @Html.EditorFor(model => model.LastName) @Html.ValidationMessageFor(model => model.LastName) </div> </div>Create.cshtml také obsahuje
@Html.AntiForgeryToken(), který funguje s atributemValidateAntiForgeryTokenv kontroleru, aby se zabránilo útokům typu forgery mezi weby .V souboru Create.cshtml nejsou vyžadovány žádné změny.
Spusťte stránku spuštěním programu, výběrem karty Studenti a následným kliknutím na Vytvořit nový.
Zadejte jména a neplatné datum a kliknutím na Vytvořit zobrazíte chybovou zprávu.
Toto je ověřování na straně serveru, které získáte ve výchozím nastavení. V pozdějším kurzu se dozvíte, jak přidat atributy, které generují kód pro ověřování na straně klienta. Následující zvýrazněný kód ukazuje kontrolu ověření modelu v metodě Create .
if (ModelState.IsValid) { db.Students.Add(student); db.SaveChanges(); return RedirectToAction("Index"); }Změňte datum na platnou hodnotu a kliknutím na Vytvořit zobrazte nového studenta na stránce Rejstřík .
Zavřete prohlížeč.
Aktualizace metody HttpPost Edit
Nahraďte metodu HttpPostAttribute
Editakce následujícím kódem:[HttpPost, ActionName("Edit")] [ValidateAntiForgeryToken] public ActionResult EditPost(int? id) { if (id == null) { return new HttpStatusCodeResult(HttpStatusCode.BadRequest); } var studentToUpdate = db.Students.Find(id); if (TryUpdateModel(studentToUpdate, "", new string[] { "LastName", "FirstMidName", "EnrollmentDate" })) { try { db.SaveChanges(); return RedirectToAction("Index"); } catch (DataException /* dex */) { //Log the error (uncomment dex variable name and add a line here to write a log. ModelState.AddModelError("", "Unable to save changes. Try again, and if the problem persists, see your system administrator."); } } return View(studentToUpdate); }Poznámka:
V Controllers\StudentController.cs
HttpGet Editmetoda (bez atributuHttpPost) používáFindmetodu k načtení vybranéStudententity, jak jste viděliDetailsv metodě. Tuto metodu nemusíte měnit.Tyto změny implementují osvědčený postup zabezpečení, aby se zabránilo nadměrnému umístění, vygeneroval
Bindscaffolder atribut a přidal entitu vytvořenou pořadačem modelu do sady entit s příznakem Změněno. Tento kód se už nedoporučuje, protožeBindatribut vymaže všechna předem existující data v polích, která nejsou uvedená v parametruInclude. V budoucnu se scaffolder kontroleru MVC aktualizuje, aby negenerovalBindatributy pro metody Edit.Nový kód přečte existující entitu a volání TryUpdateModel pro aktualizaci polí ze vstupu uživatele v publikovaných datech formuláře. Automatické sledování změn Entity Framework nastaví u entity příznak EntityState.Modified . Když se volá metoda SaveChanges , příznak způsobí, Modified že Entity Framework vytvoří příkazy SQL aktualizovat řádek databáze. Konflikty souběžnosti se ignorují a všechny sloupce řádku databáze se aktualizují, včetně sloupců, které uživatel nezměnil. (V pozdějším kurzu se dozvíte, jak zpracovat konflikty souběžnosti a jestli chcete aktualizovat pouze jednotlivá pole v databázi, můžete entitu nastavit na EntityState.Beze změny a nastavení jednotlivých polí na EntityState.Modified.)
Aby se zabránilo přesunutí, pole, která chcete aktualizovat stránkou Upravit, jsou uvedená v parametrech
TryUpdateModel. V současné době nejsou k dispozici žádná další pole, která chráníte, ale výpis polí, která má pořadač modelů svázat, zajistí, že pokud přidáte pole do datového modelu v budoucnu, budou automaticky chráněná, dokud je sem explicitně nepřidáte.V důsledku těchto změn je podpis metody HttpPost Edit metoda stejný jako HttpGet edit metoda; proto jste přejmenovali metodu EditPost.
Tip
Stavy entit a metody Attach a SaveChanges
Kontext databáze sleduje, jestli se entity v paměti synchronizují s odpovídajícími řádky v databázi a tyto informace určují, co se stane při volání
SaveChangesmetody. Když například předáte novou entitu metodě Add , stav této entity je nastaven naAdded. Když pak zavoláte metodu SaveChanges , kontext databáze vydá příkaz SQLINSERT.Entita může být v jednom z následujících stavů:
Added. Entita ještě v databázi neexistuje. MetodaSaveChangesmusí vydatINSERTpříkaz.Unchanged. Metodou není potřeba s touto entitouSaveChangesnic dělat. Při čtení entity z databáze začne entita s tímto stavem.Modified. Některé nebo všechny hodnoty vlastností entity byly změněny. MetodaSaveChangesmusí vydatUPDATEpříkaz.Deleted. Entita byla označena k odstranění. MetodaSaveChangesmusí vydatDELETEpříkaz.Detached. Entita není sledována kontextem databáze.
V desktopové aplikaci se změny stavu obvykle nastaví automaticky. V desktopovém typu aplikace přečtete entitu a provedete změny některých hodnot jeho vlastností. To způsobí, že se stav entity automaticky změní na
Modified. Při voláníSaveChangesEntity Framework vygeneruje příkaz SQLUPDATE, který aktualizuje pouze skutečné vlastnosti, které jste změnili.Odpojená povaha webových aplikací neumožňuje tuto průběžnou sekvenci. DbContext, který čte entitu, je uvolněn po vykreslení stránky.
HttpPostEditKdyž je volána metoda akce, provede se nový požadavek a máte novou instanci DbContext, takže při volání musíte ručně nastavit stav entity naModified.Hodnotu Pak při voláníSaveChangesEntity Framework aktualizuje všechny sloupce řádku databáze, protože kontext nemá způsob, jak zjistit, které vlastnosti jste změnili.Pokud chcete, aby příkaz SQL
Updateaktualizoval pouze pole, která uživatel skutečně změnil, můžete původní hodnoty uložit nějakým způsobem (například skrytá pole), aby byly k dispozici přiHttpPostEditvolání metody. Pak můžete vytvořit entituStudentpomocí původních hodnot, volat metoduAttachs původní verzí entity, aktualizovat hodnoty entity na nové hodnoty a potom volatSaveChanges.Další informace naleznete v tématu Stavy entit a SaveChanges a Místní data.Kód HTML a Razor v Views\Student\Edit.cshtml se podobá kódu, který jste viděli v souboru Create.cshtml a nejsou potřeba žádné změny.
Spusťte stránku spuštěním programu, výběrem karty Studenti a následným kliknutím na hypertextový odkaz Upravit .
Změňte některá data a klikněte na Uložit. Změněná data se zobrazí na stránce Index.
Zavřete prohlížeč.
Aktualizace stránky Odstranit
V Controllers\StudentController.cs kód šablony pro metodu HttpGetAttribute Delete používá metodu Find k načtení vybrané Student entity, jak jste viděli v metodách Details a Edit metodách. Pokud ale chcete implementovat vlastní chybovou zprávu v případě selhání volání SaveChanges , přidáte do této metody některé funkce a odpovídající zobrazení.
Jak jste viděli o operacích aktualizace a vytváření, operace odstranění vyžadují dvě metody akcí. Metoda, která je volána v reakci na požadavek GET, zobrazí zobrazení, které uživateli umožní schválit nebo zrušit operaci odstranění. Pokud ho uživatel schválí, vytvoří se žádost POST. V takovém případě HttpPost Delete se volá metoda a pak tato metoda skutečně provede operaci odstranění.
Do metody přidáte try-catch blok HttpPostAttribute Delete pro zpracování všech chyb, ke kterým může dojít při aktualizaci databáze. Pokud dojde k chybě, HttpPostAttribute Delete metoda volá metodu HttpGetAttribute Delete a předá jí parametr, který indikuje, že došlo k chybě. Metoda HttpGetAttribute Delete pak znovu zobrazí potvrzovací stránku spolu s chybovou zprávou, která uživateli dává příležitost zrušit nebo zkusit znovu.
Nahraďte metodu HttpGetAttribute
Deleteakce následujícím kódem, který spravuje hlášení chyb:public ActionResult Delete(int? id, bool? saveChangesError=false) { if (id == null) { return new HttpStatusCodeResult(HttpStatusCode.BadRequest); } if (saveChangesError.GetValueOrDefault()) { ViewBag.ErrorMessage = "Delete failed. Try again, and if the problem persists see your system administrator."; } Student student = db.Students.Find(id); if (student == null) { return HttpNotFound(); } return View(student); }Tento kód přijímá volitelný parametr , který označuje, zda byla metoda volána po selhání uložení změn. Tento parametr je
falsev případě, žeHttpGetDeletemetoda je volána bez předchozího selhání. Když je volána metodouHttpPostDeletev reakci na chybu aktualizace databáze, parametr jetruea do zobrazení se předá chybová zpráva.Nahraďte metodu HttpPostAttribute
Deleteakce (pojmenovanouDeleteConfirmed) následujícím kódem, který provede skutečnou operaci odstranění a zachytí všechny chyby aktualizace databáze.[HttpPost] [ValidateAntiForgeryToken] public ActionResult Delete(int id) { try { Student student = db.Students.Find(id); db.Students.Remove(student); db.SaveChanges(); } catch (DataException/* dex */) { //Log the error (uncomment dex variable name and add a line here to write a log. return RedirectToAction("Delete", new { id = id, saveChangesError = true }); } return RedirectToAction("Index"); }Tento kód načte vybranou entitu a potom zavolá metodu Remove , která nastaví stav entity na
Deleted. PřiSaveChangesvolání se vygeneruje příkaz SQLDELETE. Změnili jste také název metody akce zDeleteConfirmednaDelete. Vygenerovaný kód pojmenovaný metodouHttpPostDeleteDeleteConfirmedHttpPost, který metodě poskytne jedinečný podpis. (CLR vyžaduje přetížené metody, aby měly různé parametry metody.) Teď, když jsou podpisy jedinečné, můžete držet konvence MVC a použít stejný název proHttpPostmetody aHttpGetmetody delete.Pokud je zvýšení výkonu ve vysokoobsáhové aplikaci prioritou, můžete se vyhnout zbytečnému dotazu SQL k načtení řádku tak, že nahradíte řádky kódu, které volají
FindtytoRemovemetody, následujícím kódem:Student studentToDelete = new Student() { ID = id }; db.Entry(studentToDelete).State = EntityState.Deleted;Tento kód vytvoří
Studentinstanci entity pouze pomocí hodnoty primárního klíče a pak nastaví stav entity naDeleted. To je vše, co Entity Framework potřebuje k odstranění entity.Jak je uvedeno,
HttpGetDeletemetoda neodstraní data. Provedení operace odstranění v reakci na požadavek GET (nebo za tímto účelem, provedení jakékoli operace úprav, vytvoření operace nebo jakékoli jiné operace, která mění data) vytváří bezpečnostní riziko.V zobrazeních\Student\Delete.cshtml přidejte mezi nadpis a nadpis chybovou
h3zprávuh2, jak je znázorněno v následujícím příkladu:<h2>Delete</h2> <p class="error">@ViewBag.ErrorMessage</p> <h3>Are you sure you want to delete this?</h3>Spusťte stránku tak, že spustíte program, vyberete kartu Studenti a potom kliknete na hypertextový odkaz Odstranit .
Na stránce s informací, že opravdu chcete odstranit, zvolte Odstranit.
Stránka Rejstřík se zobrazí bez odstraněného studenta. (V kurzu souběžnosti uvidíte příklad kódu zpracování chyb v akci.)
Zavření připojení k databázi
Pokud chcete zavřít připojení k databázi a uvolnit prostředky, které uchovávají co nejdříve, odstraňte instanci kontextu, jakmile s ní budete hotovi. Proto kód vygenerovaný vygenerovaný kód poskytuje metodu Dispose na konci StudentController třídy v StudentController.cs, jak je znázorněno v následujícím příkladu:
protected override void Dispose(bool disposing)
{
if (disposing)
{
db.Dispose();
}
base.Dispose(disposing);
}
Základní Controller třída již implementuje IDisposable rozhraní, takže tento kód jednoduše přidá přepsání metody Dispose(bool) explicitně odstranit kontextovou instanci.
Zpracování transakcí
Ve výchozím nastavení Entity Framework implicitně implementuje transakce. Ve scénářích, ve kterých provedete změny v několika řádcích nebo tabulkách a potom zavoláte SaveChanges, entity Framework automaticky zajistí, aby všechny vaše změny proběhly úspěšně nebo všechny selžou. Pokud se některé změny dokončí nejprve a dojde k chybě, tyto změny se automaticky vrátí zpět. Scénáře, ve kterých potřebujete větší kontrolu – například pokud chcete zahrnout operace provedené mimo Entity Framework v transakci – viz Práce s transakcemi.
Získání kódu
Další materiály
Teď máte úplnou sadu stránek, které pro entity provádějí jednoduché operace Student CRUD. Použili jste pomocné rutiny MVC k vygenerování prvků uživatelského rozhraní pro datová pole. Další informace o pomocných rutinách MVC najdete v tématu Vykreslení formuláře pomocí pomocných rutin HTML (článek je pro MVC 3, ale stále je relevantní pro MVC 5).
Odkazy na další prostředky EF 6 najdete v tématu ASP.NET Přístup k datům – doporučené zdroje informací.
Další kroky
V tomto kurzu se naučíte:
- Vytvoření stránky Podrobností
- Aktualizace stránky Vytvořit
- Aktualizace metody HttpPost Edit
- Aktualizace stránky Odstranit
- Uzavřená připojení k databázi
- Zpracovávané transakce
V dalším článku se dozvíte, jak do projektu přidat řazení, filtrování a stránkování.