Kurz: Aktualizace souvisejících dat – ASP.NET MVC pomocí EF Core
V předchozím kurzu jste zobrazili související data; v tomto kurzu aktualizujete související data aktualizací polí cizího klíče a vlastností navigace.
Následující ilustrace ukazují některé stránky, se kterými budete pracovat.
V tomto kurzu jste:
- Přizpůsobení stránek kurzů
- Přidat stránku pro úpravy instruktorů
- Přidání kurzů na stránku Upravit
- Aktualizovat stránku Odstranit
- Přidání umístění office a kurzů na stránku Vytvořit
Požadavky
Přizpůsobení stránek kurzů
Když se vytvoří nová Course
entita, musí mít vztah k existujícímu oddělení. Aby se to usnadnilo, obsahuje vygenerovaný kód metody kontroleru a zobrazení Pro vytvoření a úpravy, která obsahují rozevírací seznam pro výběr oddělení. Rozevírací seznam nastaví vlastnost cizího Course.DepartmentID
klíče a to je vše, co Entity Framework potřebuje k načtení Department
navigační vlastnosti s příslušnou Department
entitou. Vygenerovaný kód použijete, ale mírně ho změníte tak, abyste přidali zpracování chyb a seřadili rozevírací seznam.
Odstraňte CoursesController.cs
čtyři metody Create and Edit a nahraďte je následujícím kódem:
public IActionResult Create()
{
PopulateDepartmentsDropDownList();
return View();
}
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Create([Bind("CourseID,Credits,DepartmentID,Title")] Course course)
{
if (ModelState.IsValid)
{
_context.Add(course);
await _context.SaveChangesAsync();
return RedirectToAction(nameof(Index));
}
PopulateDepartmentsDropDownList(course.DepartmentID);
return View(course);
}
public async Task<IActionResult> Edit(int? id)
{
if (id == null)
{
return NotFound();
}
var course = await _context.Courses
.AsNoTracking()
.FirstOrDefaultAsync(m => m.CourseID == id);
if (course == null)
{
return NotFound();
}
PopulateDepartmentsDropDownList(course.DepartmentID);
return View(course);
}
[HttpPost, ActionName("Edit")]
[ValidateAntiForgeryToken]
public async Task<IActionResult> EditPost(int? id)
{
if (id == null)
{
return NotFound();
}
var courseToUpdate = await _context.Courses
.FirstOrDefaultAsync(c => c.CourseID == id);
if (await TryUpdateModelAsync<Course>(courseToUpdate,
"",
c => c.Credits, c => c.DepartmentID, c => c.Title))
{
try
{
await _context.SaveChangesAsync();
}
catch (DbUpdateException /* ex */)
{
//Log the error (uncomment ex variable name and write a log.)
ModelState.AddModelError("", "Unable to save changes. " +
"Try again, and if the problem persists, " +
"see your system administrator.");
}
return RedirectToAction(nameof(Index));
}
PopulateDepartmentsDropDownList(courseToUpdate.DepartmentID);
return View(courseToUpdate);
}
Edit
Po metodě HttpPost vytvořte novou metodu, která načte informace o oddělení pro rozevírací seznam.
private void PopulateDepartmentsDropDownList(object selectedDepartment = null)
{
var departmentsQuery = from d in _context.Departments
orderby d.Name
select d;
ViewBag.DepartmentID = new SelectList(departmentsQuery.AsNoTracking(), "DepartmentID", "Name", selectedDepartment);
}
Metoda PopulateDepartmentsDropDownList
získá seznam všech oddělení seřazených podle názvu, vytvoří SelectList
kolekci pro rozevírací seznam a předá kolekci do zobrazení v ViewBag
. Metoda přijímá volitelný selectedDepartment
parametr, který umožňuje volajícímu kódu určit položku, která bude vybrána při vykreslení rozevíracího seznamu. Zobrazení předá pomocnému rutině <select>
značky název "DepartmentID" a pomocník pak ví, že hledá v objektu ViewBag
SelectList
název "DepartmentID".
Metoda HttpGet Create
volá metodu PopulateDepartmentsDropDownList
bez nastavení vybrané položky, protože pro nový kurz se oddělení ještě nenaváže:
public IActionResult Create()
{
PopulateDepartmentsDropDownList();
return View();
}
Metoda HttpGet Edit
nastaví vybranou položku na základě ID oddělení, které je již přiřazeno k úpravě kurzu:
public async Task<IActionResult> Edit(int? id)
{
if (id == null)
{
return NotFound();
}
var course = await _context.Courses
.AsNoTracking()
.FirstOrDefaultAsync(m => m.CourseID == id);
if (course == null)
{
return NotFound();
}
PopulateDepartmentsDropDownList(course.DepartmentID);
return View(course);
}
Metody HttpPost pro obě Create
a Edit
také zahrnují kód, který nastaví vybranou položku při opětovném zobrazení stránky po chybě. Tím zajistíte, že když se stránka znovu zobrazí, aby se zobrazila chybová zpráva, které je vybrané oddělení, zůstane vybrané.
Přidat. Metody AsNoTracking k podrobnostem a odstranění
Chcete-li optimalizovat výkon stránek Podrobnosti kurzu a Odstranit, přidejte AsNoTracking
volání do Details
metod HttpGet Delete
.
public async Task<IActionResult> Details(int? id)
{
if (id == null)
{
return NotFound();
}
var course = await _context.Courses
.Include(c => c.Department)
.AsNoTracking()
.FirstOrDefaultAsync(m => m.CourseID == id);
if (course == null)
{
return NotFound();
}
return View(course);
}
public async Task<IActionResult> Delete(int? id)
{
if (id == null)
{
return NotFound();
}
var course = await _context.Courses
.Include(c => c.Department)
.AsNoTracking()
.FirstOrDefaultAsync(m => m.CourseID == id);
if (course == null)
{
return NotFound();
}
return View(course);
}
Úprava zobrazení kurzu
Do Views/Courses/Create.cshtml
rozevíracího seznamu Oddělení přidejte možnost Vybrat oddělení, změňte titulek z Id oddělení na Oddělení a přidejte ověřovací zprávu.
<div class="form-group">
<label asp-for="Department" class="control-label"></label>
<select asp-for="DepartmentID" class="form-control" asp-items="ViewBag.DepartmentID">
<option value="">-- Select Department --</option>
</select>
<span asp-validation-for="DepartmentID" class="text-danger" />
</div>
Proveďte Views/Courses/Edit.cshtml
stejnou změnu pro pole Oddělení, ve které jste právě provedli Create.cshtml
.
Views/Courses/Edit.cshtml
Do pole Název přidejte také pole číslo kurzu. Vzhledem k tomu, že číslo kurzu je primárním klíčem, zobrazí se, ale nedá se změnit.
<div class="form-group">
<label asp-for="CourseID" class="control-label"></label>
<div>@Html.DisplayFor(model => model.CourseID)</div>
</div>
V zobrazení pro úpravy už je skryté pole (<input type="hidden">
) pro číslo kurzu. Přidání pomocné rutiny <label>
značek eliminuje potřebu skrytého pole, protože nezpůsobí zahrnutí čísla kurzu do publikovaných dat, když uživatel klikne na uložit na stránce Upravit .
Přidejte Views/Courses/Delete.cshtml
do horní části pole číslo kurzu a změňte ID oddělení na název oddělení.
@model ContosoUniversity.Models.Course
@{
ViewData["Title"] = "Delete";
}
<h2>Delete</h2>
<h3>Are you sure you want to delete this?</h3>
<div>
<h4>Course</h4>
<hr />
<dl class="row">
<dt class="col-sm-2">
@Html.DisplayNameFor(model => model.CourseID)
</dt>
<dd class="col-sm-10">
@Html.DisplayFor(model => model.CourseID)
</dd>
<dt class="col-sm-2">
@Html.DisplayNameFor(model => model.Title)
</dt>
<dd class="col-sm-10">
@Html.DisplayFor(model => model.Title)
</dd>
<dt class="col-sm-2">
@Html.DisplayNameFor(model => model.Credits)
</dt>
<dd class="col-sm-10">
@Html.DisplayFor(model => model.Credits)
</dd>
<dt class="col-sm-2">
@Html.DisplayNameFor(model => model.Department)
</dt>
<dd class="col-sm-10">
@Html.DisplayFor(model => model.Department.Name)
</dd>
</dl>
<form asp-action="Delete">
<div class="form-actions no-color">
<input type="submit" value="Delete" class="btn btn-default" /> |
<a asp-action="Index">Back to List</a>
</div>
</form>
</div>
Proveďte Views/Courses/Details.cshtml
stejnou změnu, pro kterou jste právě udělali Delete.cshtml
.
Otestování stránek kurzu
Spusťte aplikaci, vyberte kartu Kurzy , klikněte na Vytvořit nový a zadejte data pro nový kurz:
Klikněte na Vytvořit. Stránka Index kurzů se zobrazí s novým kurzem přidaným do seznamu. Název oddělení v seznamu stránek indexu pochází z navigační vlastnosti, která ukazuje, že relace byla správně vytvořena.
Klikněte na upravit kurz na stránce Index kurzů.
Změňte data na stránce a klikněte na Uložit. Stránka Index kurzů se zobrazí s aktualizovanými daty kurzu.
Přidat stránku pro úpravy instruktorů
Když upravujete záznam instruktora, chcete mít možnost aktualizovat zadání kanceláře instruktora. Entita Instructor
má relaci 1:nulu nebo 1 s entitou OfficeAssignment
, což znamená, že váš kód musí zpracovávat následující situace:
Pokud uživatel vymaže přiřazení kanceláře a původně měl hodnotu, odstraňte entitu
OfficeAssignment
.Pokud uživatel zadá hodnotu přiřazení office a původně byla prázdná, vytvořte novou
OfficeAssignment
entitu.Pokud uživatel změní hodnotu přiřazení kanceláře, změňte hodnotu v existující
OfficeAssignment
entitě.
Aktualizace kontroleru instruktorů
Změňte InstructorsController.cs
kód v metodě HttpGet Edit
tak, aby načítá vlastnost navigace a volání AsNoTracking
entity OfficeAssignment
Instruktor:
public async Task<IActionResult> Edit(int? id)
{
if (id == null)
{
return NotFound();
}
var instructor = await _context.Instructors
.Include(i => i.OfficeAssignment)
.AsNoTracking()
.FirstOrDefaultAsync(m => m.ID == id);
if (instructor == null)
{
return NotFound();
}
return View(instructor);
}
Nahraďte metodu HttpPost Edit
následujícím kódem pro zpracování aktualizací přiřazení office:
[HttpPost, ActionName("Edit")]
[ValidateAntiForgeryToken]
public async Task<IActionResult> EditPost(int? id)
{
if (id == null)
{
return NotFound();
}
var instructorToUpdate = await _context.Instructors
.Include(i => i.OfficeAssignment)
.FirstOrDefaultAsync(s => s.ID == id);
if (await TryUpdateModelAsync<Instructor>(
instructorToUpdate,
"",
i => i.FirstMidName, i => i.LastName, i => i.HireDate, i => i.OfficeAssignment))
{
if (String.IsNullOrWhiteSpace(instructorToUpdate.OfficeAssignment?.Location))
{
instructorToUpdate.OfficeAssignment = null;
}
try
{
await _context.SaveChangesAsync();
}
catch (DbUpdateException /* ex */)
{
//Log the error (uncomment ex variable name and write a log.)
ModelState.AddModelError("", "Unable to save changes. " +
"Try again, and if the problem persists, " +
"see your system administrator.");
}
return RedirectToAction(nameof(Index));
}
return View(instructorToUpdate);
}
Kód provede následující:
Změní název metody tak, aby
EditPost
podpis byl nyní stejný jako metoda HttpGetEdit
(ActionName
atribut určuje, že/Edit/
adresa URL se stále používá).Získá aktuální
Instructor
entitu z databáze pomocí dychtivého načítání proOfficeAssignment
navigační vlastnost. To je stejné jako to, co jste udělali v metodě HttpGetEdit
.Aktualizuje načtenou
Instructor
entitu hodnotami z pořadače modelu. PřetíženíTryUpdateModel
umožňuje deklarovat vlastnosti, které chcete zahrnout. Tím zabráníte nadměrnému účtování, jak je vysvětleno v druhém kurzu.if (await TryUpdateModelAsync<Instructor>( instructorToUpdate, "", i => i.FirstMidName, i => i.LastName, i => i.HireDate, i => i.OfficeAssignment))
Pokud je umístění kanceláře prázdné, nastaví
Instructor.OfficeAssignment
vlastnost na hodnotu null, aby se související řádek vOfficeAssignment
tabulce odstranil.if (String.IsNullOrWhiteSpace(instructorToUpdate.OfficeAssignment?.Location)) { instructorToUpdate.OfficeAssignment = null; }
Uloží změny do databáze.
Aktualizace zobrazení pro úpravy instruktora
V Views/Instructors/Edit.cshtml
části , přidejte nové pole pro úpravu umístění kanceláře, na konci před tlačítkem Uložit :
<div class="form-group">
<label asp-for="OfficeAssignment.Location" class="control-label"></label>
<input asp-for="OfficeAssignment.Location" class="form-control" />
<span asp-validation-for="OfficeAssignment.Location" class="text-danger" />
</div>
Spusťte aplikaci, vyberte kartu Instruktory a potom klikněte na Upravit u instruktora. Změňte umístění Office a klikněte na Uložit.
Přidání kurzů na stránku Upravit
Instruktoři mohou učit libovolný počet kurzů. Teď vylepšíte stránku Pro úpravy instruktora přidáním možnosti změnit zadání kurzu pomocí skupiny zaškrtávacích políček, jak je znázorněno na následujícím snímku obrazovky:
Vztah mezi entitami Course
a Instructor
entitami je M:N. Pokud chcete přidat a odebrat relace, přidáte a odeberete entity do a ze CourseAssignments
sady entit join.
Uživatelské rozhraní, které umožňuje změnit, ke kterým kurzům je instruktor přiřazen, je skupina zaškrtávacích políček. Zobrazí se zaškrtávací políčko pro každý kurz v databázi a ty, ke kterým je instruktor aktuálně přiřazený, jsou vybrány. Uživatel může zaškrtnutím nebo zrušením zaškrtnutí políček změnit přiřazení kurzu. Pokud je počet kurzů mnohem větší, pravděpodobně byste chtěli použít jinou metodu prezentace dat v zobrazení, ale ke vytváření nebo odstraňování relací byste použili stejnou metodu manipulace s entitou spojení.
Aktualizace kontroleru instruktorů
Pokud chcete do zobrazení zadat data pro seznam zaškrtávacích políček, použijete třídu modelu zobrazení.
Vytvořte AssignedCourseData.cs
ve složce SchoolViewModels a nahraďte stávající kód následujícím kódem:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace ContosoUniversity.Models.SchoolViewModels
{
public class AssignedCourseData
{
public int CourseID { get; set; }
public string Title { get; set; }
public bool Assigned { get; set; }
}
}
V InstructorsController.cs
souboru nahraďte metodu HttpGet Edit
následujícím kódem. Změny jsou zvýrazněné.
public async Task<IActionResult> Edit(int? id)
{
if (id == null)
{
return NotFound();
}
var instructor = await _context.Instructors
.Include(i => i.OfficeAssignment)
.Include(i => i.CourseAssignments).ThenInclude(i => i.Course)
.AsNoTracking()
.FirstOrDefaultAsync(m => m.ID == id);
if (instructor == null)
{
return NotFound();
}
PopulateAssignedCourseData(instructor);
return View(instructor);
}
private void PopulateAssignedCourseData(Instructor instructor)
{
var allCourses = _context.Courses;
var instructorCourses = new HashSet<int>(instructor.CourseAssignments.Select(c => c.CourseID));
var viewModel = new List<AssignedCourseData>();
foreach (var course in allCourses)
{
viewModel.Add(new AssignedCourseData
{
CourseID = course.CourseID,
Title = course.Title,
Assigned = instructorCourses.Contains(course.CourseID)
});
}
ViewData["Courses"] = viewModel;
}
Kód přidává dychtivé načítání pro Courses
navigační vlastnost a volá novou PopulateAssignedCourseData
metodu, která poskytuje informace pro pole zaškrtávacího políčka pomocí AssignedCourseData
třídy modelu zobrazení.
Kód v PopulateAssignedCourseData
metodě čte všechny Course
entity za účelem načtení seznamu kurzů pomocí třídy modelu zobrazení. Pro každý kurz kód zkontroluje, jestli kurz existuje ve vlastnosti navigace instruktora Courses
. Pokud chcete vytvořit efektivní vyhledávání při kontrole, jestli je kurz přiřazen instruktorovi, kurzy přiřazené instruktorovi se vloží do HashSet
kolekce. Vlastnost Assigned
je nastavena na hodnotu true pro kurzy, ke kterým je instruktor přiřazen. Toto zobrazení použije tuto vlastnost k určení, která zaškrtávací políčka se musí zobrazit jako vybraná. Nakonec se seznam předá zobrazení v ViewData
souboru .
Dále přidejte kód, který se spustí, když uživatel klikne na Uložit. EditPost
Nahraďte metodu následujícím kódem a přidejte novou metodu, která aktualizuje Courses
navigační vlastnost entity Instruktor.
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Edit(int? id, string[] selectedCourses)
{
if (id == null)
{
return NotFound();
}
var instructorToUpdate = await _context.Instructors
.Include(i => i.OfficeAssignment)
.Include(i => i.CourseAssignments)
.ThenInclude(i => i.Course)
.FirstOrDefaultAsync(m => m.ID == id);
if (await TryUpdateModelAsync<Instructor>(
instructorToUpdate,
"",
i => i.FirstMidName, i => i.LastName, i => i.HireDate, i => i.OfficeAssignment))
{
if (String.IsNullOrWhiteSpace(instructorToUpdate.OfficeAssignment?.Location))
{
instructorToUpdate.OfficeAssignment = null;
}
UpdateInstructorCourses(selectedCourses, instructorToUpdate);
try
{
await _context.SaveChangesAsync();
}
catch (DbUpdateException /* ex */)
{
//Log the error (uncomment ex variable name and write a log.)
ModelState.AddModelError("", "Unable to save changes. " +
"Try again, and if the problem persists, " +
"see your system administrator.");
}
return RedirectToAction(nameof(Index));
}
UpdateInstructorCourses(selectedCourses, instructorToUpdate);
PopulateAssignedCourseData(instructorToUpdate);
return View(instructorToUpdate);
}
private void UpdateInstructorCourses(string[] selectedCourses, Instructor instructorToUpdate)
{
if (selectedCourses == null)
{
instructorToUpdate.CourseAssignments = new List<CourseAssignment>();
return;
}
var selectedCoursesHS = new HashSet<string>(selectedCourses);
var instructorCourses = new HashSet<int>
(instructorToUpdate.CourseAssignments.Select(c => c.Course.CourseID));
foreach (var course in _context.Courses)
{
if (selectedCoursesHS.Contains(course.CourseID.ToString()))
{
if (!instructorCourses.Contains(course.CourseID))
{
instructorToUpdate.CourseAssignments.Add(new CourseAssignment { InstructorID = instructorToUpdate.ID, CourseID = course.CourseID });
}
}
else
{
if (instructorCourses.Contains(course.CourseID))
{
CourseAssignment courseToRemove = instructorToUpdate.CourseAssignments.FirstOrDefault(i => i.CourseID == course.CourseID);
_context.Remove(courseToRemove);
}
}
}
}
Podpis metody se teď liší od metody HttpGet Edit
, takže název metody se změní z EditPost
zpět na Edit
.
Vzhledem k tomu, že zobrazení neobsahuje kolekci entit kurzu, nemůže binder modelu automaticky aktualizovat CourseAssignments
navigační vlastnost. Místo použití binderu CourseAssignments
modelu k aktualizaci navigační vlastnosti to uděláte v nové UpdateInstructorCourses
metodě. Proto je potřeba vlastnost vyloučit z vazby CourseAssignments
modelu. To nevyžaduje žádnou změnu kódu, který volá TryUpdateModel
, protože používáte přetížení, které vyžaduje explicitní schválení a CourseAssignments
není v seznamu zahrnutí.
Pokud nebyly zaškrtnuté žádné zaškrtávací políčka, kód inicializuje UpdateInstructorCourses
navigační vlastnost s prázdnou CourseAssignments
kolekcí a vrátí:
private void UpdateInstructorCourses(string[] selectedCourses, Instructor instructorToUpdate)
{
if (selectedCourses == null)
{
instructorToUpdate.CourseAssignments = new List<CourseAssignment>();
return;
}
var selectedCoursesHS = new HashSet<string>(selectedCourses);
var instructorCourses = new HashSet<int>
(instructorToUpdate.CourseAssignments.Select(c => c.Course.CourseID));
foreach (var course in _context.Courses)
{
if (selectedCoursesHS.Contains(course.CourseID.ToString()))
{
if (!instructorCourses.Contains(course.CourseID))
{
instructorToUpdate.CourseAssignments.Add(new CourseAssignment { InstructorID = instructorToUpdate.ID, CourseID = course.CourseID });
}
}
else
{
if (instructorCourses.Contains(course.CourseID))
{
CourseAssignment courseToRemove = instructorToUpdate.CourseAssignments.FirstOrDefault(i => i.CourseID == course.CourseID);
_context.Remove(courseToRemove);
}
}
}
}
Kód pak prochází všechny kurzy v databázi a kontroluje jednotlivé kurzy proti kurzům, které jsou aktuálně přiřazeny instruktorovi, a ty, které byly vybrány v zobrazení. Aby bylo snazší efektivní vyhledávání, jsou tyto dvě kolekce uloženy v HashSet
objektech.
Pokud je zaškrtnuté políčko pro kurz, ale kurz není v Instructor.CourseAssignments
navigační vlastnosti, kurz se přidá do kolekce v navigační vlastnosti.
private void UpdateInstructorCourses(string[] selectedCourses, Instructor instructorToUpdate)
{
if (selectedCourses == null)
{
instructorToUpdate.CourseAssignments = new List<CourseAssignment>();
return;
}
var selectedCoursesHS = new HashSet<string>(selectedCourses);
var instructorCourses = new HashSet<int>
(instructorToUpdate.CourseAssignments.Select(c => c.Course.CourseID));
foreach (var course in _context.Courses)
{
if (selectedCoursesHS.Contains(course.CourseID.ToString()))
{
if (!instructorCourses.Contains(course.CourseID))
{
instructorToUpdate.CourseAssignments.Add(new CourseAssignment { InstructorID = instructorToUpdate.ID, CourseID = course.CourseID });
}
}
else
{
if (instructorCourses.Contains(course.CourseID))
{
CourseAssignment courseToRemove = instructorToUpdate.CourseAssignments.FirstOrDefault(i => i.CourseID == course.CourseID);
_context.Remove(courseToRemove);
}
}
}
}
Pokud není zaškrtnuté políčko pro kurz, ale kurz je v Instructor.CourseAssignments
navigační vlastnosti, kurz se z navigační vlastnosti odebere.
private void UpdateInstructorCourses(string[] selectedCourses, Instructor instructorToUpdate)
{
if (selectedCourses == null)
{
instructorToUpdate.CourseAssignments = new List<CourseAssignment>();
return;
}
var selectedCoursesHS = new HashSet<string>(selectedCourses);
var instructorCourses = new HashSet<int>
(instructorToUpdate.CourseAssignments.Select(c => c.Course.CourseID));
foreach (var course in _context.Courses)
{
if (selectedCoursesHS.Contains(course.CourseID.ToString()))
{
if (!instructorCourses.Contains(course.CourseID))
{
instructorToUpdate.CourseAssignments.Add(new CourseAssignment { InstructorID = instructorToUpdate.ID, CourseID = course.CourseID });
}
}
else
{
if (instructorCourses.Contains(course.CourseID))
{
CourseAssignment courseToRemove = instructorToUpdate.CourseAssignments.FirstOrDefault(i => i.CourseID == course.CourseID);
_context.Remove(courseToRemove);
}
}
}
}
Aktualizace zobrazení instruktora
Do Views/Instructors/Edit.cshtml
pole Kurzy přidejte pole Kurzy s polem zaškrtávacích políček přidáním následujícího kódu bezprostředně za div
prvky pole Office a před div
prvek tlačítka Uložit .
Poznámka
Když kód vložíte do sady Visual Studio, můžou se konce řádků změnit způsobem, který kód přeruší. Pokud se kód po vložení liší, můžete automatické formátování vrátit jedním stisknutím kombinace kláves Ctrl+Z zpět. Tím se opraví konce řádků, aby vypadaly, jak vidíte tady. Odsazení nemusí být dokonalé, ale @:</tr><tr>
čáry , @:<td>
@:</td>
a @:</tr>
řádky musí být na jednom řádku, jak je znázorněno, nebo se zobrazí chyba za běhu. Když vyberete blok nového kódu, stiskněte třikrát klávesu Tab, aby se nový kód zarovnál s existujícím kódem. Tento problém je opravený v sadě Visual Studio 2019.
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<table>
<tr>
@{
int cnt = 0;
List<ContosoUniversity.Models.SchoolViewModels.AssignedCourseData> courses = ViewBag.Courses;
foreach (var course in courses)
{
if (cnt++ % 3 == 0)
{
@:</tr><tr>
}
@:<td>
<input type="checkbox"
name="selectedCourses"
value="@course.CourseID"
@(Html.Raw(course.Assigned ? "checked=\"checked\"" : "")) />
@course.CourseID @: @course.Title
@:</td>
}
@:</tr>
}
</table>
</div>
</div>
Tento kód vytvoří tabulku HTML se třemi sloupci. V každém sloupci je zaškrtávací políčko následované titulkem, který se skládá z čísla a názvu kurzu. Zaškrtávací políčka mají stejný název ("selectedCourses"), který informuje binder modelu, že se mají považovat za skupinu. Atribut hodnoty každého zaškrtávacího políčka je nastaven na hodnotu .CourseID
Když se stránka publikuje, pořadač modelu předá matici kontroleru, který se skládá z CourseID
hodnot pouze pro zaškrtávací políčka, která jsou vybrána.
Když jsou zaškrtávací políčka původně vykreslena, ty, které jsou určené pro kurzy přiřazené instruktorovi, zkontrolovaly atributy, které je vyberou (zobrazí je zaškrtnuté).
Spusťte aplikaci, vyberte kartu Instruktory a kliknutím na Upravit na instruktoru zobrazte stránku Upravit .
Změňte zadání kurzu a klikněte na Uložit. Změny, které provedete, se projeví na stránce Index.
Poznámka
Přístup, který jsme zde provedli k úpravě dat kurzu instruktora, funguje dobře, když existuje omezený počet kurzů. U kolekcí, které jsou mnohem větší, by se vyžadovalo jiné uživatelské rozhraní a jiná metoda aktualizace.
Aktualizovat stránku Odstranit
Odstraňte InstructorsController.cs
metodu DeleteConfirmed
a vložte následující kód na jeho místo.
[HttpPost, ActionName("Delete")]
[ValidateAntiForgeryToken]
public async Task<IActionResult> DeleteConfirmed(int id)
{
Instructor instructor = await _context.Instructors
.Include(i => i.CourseAssignments)
.SingleAsync(i => i.ID == id);
var departments = await _context.Departments
.Where(d => d.InstructorID == id)
.ToListAsync();
departments.ForEach(d => d.InstructorID = null);
_context.Instructors.Remove(instructor);
await _context.SaveChangesAsync();
return RedirectToAction(nameof(Index));
}
Tento kód provede následující změny:
Načítá pro navigační vlastnost dychtivou načítání
CourseAssignments
. Musíte zahrnout tento soubor nebo efS nebude vědět o souvisejícíchCourseAssignment
entitách a neodstraníte je. Abyste se vyhnuli tomu, že byste je zde museli číst, můžete v databázi nakonfigurovat kaskádové odstranění.Pokud je instruktor, který má být odstraněn, přiřazen jako správce všech oddělení, odebere zadání instruktora z těchto oddělení.
Přidání umístění office a kurzů na stránku Vytvořit
Odstraňte InstructorsController.cs
metody HttpGet a HttpPost Create
a pak přidejte na jejich místo následující kód:
public IActionResult Create()
{
var instructor = new Instructor();
instructor.CourseAssignments = new List<CourseAssignment>();
PopulateAssignedCourseData(instructor);
return View();
}
// POST: Instructors/Create
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Create([Bind("FirstMidName,HireDate,LastName,OfficeAssignment")] Instructor instructor, string[] selectedCourses)
{
if (selectedCourses != null)
{
instructor.CourseAssignments = new List<CourseAssignment>();
foreach (var course in selectedCourses)
{
var courseToAdd = new CourseAssignment { InstructorID = instructor.ID, CourseID = int.Parse(course) };
instructor.CourseAssignments.Add(courseToAdd);
}
}
if (ModelState.IsValid)
{
_context.Add(instructor);
await _context.SaveChangesAsync();
return RedirectToAction(nameof(Index));
}
PopulateAssignedCourseData(instructor);
return View(instructor);
}
Tento kód je podobný tomu, co jste viděli u Edit
metod s výjimkou toho, že zpočátku nejsou vybrány žádné kurzy. Metoda HttpGet Create
volá metodu PopulateAssignedCourseData
ne, protože mohou být vybrány kurzy, ale aby bylo možné poskytnout prázdnou kolekci smyčky foreach
v zobrazení (jinak by kód zobrazení vyvolá výjimku null odkaz).
Metoda HttpPost Create
přidá každý vybraný kurz do CourseAssignments
navigační vlastnosti předtím, než zkontroluje chyby ověření a přidá do databáze nového instruktora. Kurzy se přidají i v případě, že dojde k chybám modelu, aby se zobrazily chyby modelu (například uživatel s neplatným datem) a stránka se znovu zobrazí s chybovou zprávou, všechny provedené výběry kurzu se automaticky obnoví.
Všimněte si, že abyste mohli přidat kurzy do CourseAssignments
navigační vlastnosti, musíte vlastnost inicializovat jako prázdnou kolekci:
instructor.CourseAssignments = new List<CourseAssignment>();
Jako alternativu k tomu v kódu kontroleru byste to mohli udělat v Instructor
modelu tak, že změníte getter vlastnosti tak, aby automaticky vytvořil kolekci, pokud neexistuje, jak je znázorněno v následujícím příkladu:
private ICollection<CourseAssignment> _courseAssignments;
public ICollection<CourseAssignment> CourseAssignments
{
get
{
return _courseAssignments ?? (_courseAssignments = new List<CourseAssignment>());
}
set
{
_courseAssignments = value;
}
}
Pokud vlastnost tímto způsobem upravíte CourseAssignments
, můžete odebrat explicitní kód inicializace vlastností v kontroleru.
Do Views/Instructor/Create.cshtml
pole pro umístění kanceláře přidejte textové pole a zaškrtávací políčka pro kurzy před tlačítkem Odeslat. Stejně jako v případě stránky Pro úpravy opravte formátování, pokud Visual Studio přeformátuje kód při vložení.
<div class="form-group">
<label asp-for="OfficeAssignment.Location" class="control-label"></label>
<input asp-for="OfficeAssignment.Location" class="form-control" />
<span asp-validation-for="OfficeAssignment.Location" class="text-danger" />
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<table>
<tr>
@{
int cnt = 0;
List<ContosoUniversity.Models.SchoolViewModels.AssignedCourseData> courses = ViewBag.Courses;
foreach (var course in courses)
{
if (cnt++ % 3 == 0)
{
@:</tr><tr>
}
@:<td>
<input type="checkbox"
name="selectedCourses"
value="@course.CourseID"
@(Html.Raw(course.Assigned ? "checked=\"checked\"" : "")) />
@course.CourseID @: @course.Title
@:</td>
}
@:</tr>
}
</table>
</div>
</div>
Otestujte spuštěním aplikace a vytvořením instruktora.
Zpracování transakcí
Jak je vysvětleno v kurzu CRUD, Entity Framework implicitně implementuje transakce. V situacích, kdy potřebujete větší kontrolu – například pokud chcete zahrnout operace provedené mimo Entity Framework do transakce – viz Transakce.
Získání kódu
Stáhněte nebo zobrazte dokončenou aplikaci.
Další kroky
V tomto kurzu jste:
- Přizpůsobené stránky kurzů
- Přidání stránky Pro úpravy instruktorů
- Přidání kurzů na stránku Upravit
- Aktualizovaná stránka Odstranit
- Přidání umístění office a kurzů na stránku Vytvořit
V dalším kurzu se dozvíte, jak zvládnout konflikty souběžnosti.