Aktualizace souvisejících dat pomocí entity Framework v aplikaci ASP.NET MVC (6 z 10)
Tom Dykstra
Ukázková webová aplikace Contoso University ukazuje, jak vytvářet aplikace ASP.NET MVC 4 pomocí entity Framework 5 Code First a sady Visual Studio 2012. Informace o sérii kurzů najdete v prvním kurzu série.
Poznámka:
Pokud narazíte na problém, který nemůžete vyřešit, stáhněte si dokončenou kapitolu a zkuste problém reprodukovat. Obecně můžete najít řešení problému porovnáním kódu s dokončeným kódem. Informace o některých běžných chybách a jejich řešení najdete v tématu Chyby a alternativní řešení.
V předchozím kurzu jste zobrazili související data; v tomto kurzu aktualizujete související data. U většiny relací to lze provést aktualizací příslušných polí cizího klíče. U relací M:N nezpřístupňuje Entity Framework přímo tabulku spojení, takže je nutné explicitně přidávat a odebírat entity do a z příslušných navigačních vlastností.
Následující ilustrace znázorňují stránky, se kterými budete pracovat.
Přizpůsobení stránek pro vytváření a úpravy pro kurzy
Když se vytvoří nová entita kurzu, musí mít vztah k existujícímu oddělení. Aby se to usnadnilo, vygenerovaný kód obsahuje 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, že přidáte zpracování chyb a seřadíte rozevírací seznam.
V CourseController.cs odstraňte čtyři Edit
metody a Create
nahraďte je následujícím kódem:
public ActionResult Create()
{
PopulateDepartmentsDropDownList();
return View();
}
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create(
[Bind(Include = "CourseID,Title,Credits,DepartmentID")]
Course course)
{
try
{
if (ModelState.IsValid)
{
db.Courses.Add(course);
db.SaveChanges();
return RedirectToAction("Index");
}
}
catch (DataException /* dex */)
{
//Log the error (uncomment dex variable name after DataException 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.");
}
PopulateDepartmentsDropDownList(course.DepartmentID);
return View(course);
}
public ActionResult Edit(int id)
{
Course course = db.Courses.Find(id);
PopulateDepartmentsDropDownList(course.DepartmentID);
return View(course);
}
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Edit(
[Bind(Include = "CourseID,Title,Credits,DepartmentID")]
Course course)
{
try
{
if (ModelState.IsValid)
{
db.Entry(course).State = EntityState.Modified;
db.SaveChanges();
return RedirectToAction("Index");
}
}
catch (DataException /* dex */)
{
//Log the error (uncomment dex variable name after DataException 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.");
}
PopulateDepartmentsDropDownList(course.DepartmentID);
return View(course);
}
private void PopulateDepartmentsDropDownList(object selectedDepartment = null)
{
var departmentsQuery = from d in db.Departments
orderby d.Name
select d;
ViewBag.DepartmentID = new SelectList(departmentsQuery, "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í ve ViewBag
vlastnosti. 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é rutině DropDownList
název DepartmentID
a pomocník pak ví, že hledá v objektu ViewBag
pojmenovaný SelectList
DepartmentID
.
Metoda HttpGet
Create
volá metodu PopulateDepartmentsDropDownList
bez nastavení vybrané položky, protože pro nový kurz není oddělení ještě vytvořeno:
public ActionResult 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 ActionResult Edit(int id)
{
Course course = db.Courses.Find(id);
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ě:
catch (DataException /* dex */)
{
//Log the error (uncomment dex variable name after DataException 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.");
}
PopulateDepartmentsDropDownList(course.DepartmentID);
return View(course);
Tento kód zajistí, že když se stránka znovu zobrazí, aby se zobrazila chybová zpráva bez ohledu na to, které oddělení bylo vybráno, zůstane vybrané.
V zobrazení\Course\Create.cshtml přidejte zvýrazněný kód a vytvořte nové pole čísla kurzu před pole Název . Jak je vysvětleno v předchozím kurzu, pole primárního klíče se ve výchozím nastavení nevygenerují, ale tento primární klíč je smysluplný, takže chcete, aby uživatel mohl zadat hodnotu klíče.
@model ContosoUniversity.Models.Course
@{
ViewBag.Title = "Create";
}
<h2>Create</h2>
@using (Html.BeginForm())
{
@Html.AntiForgeryToken()
@Html.ValidationSummary(true)
<fieldset>
<legend>Course</legend>
<div class="editor-label">
@Html.LabelFor(model => model.CourseID)
</div>
<div class="editor-field">
@Html.EditorFor(model => model.CourseID)
@Html.ValidationMessageFor(model => model.CourseID)
</div>
<div class="editor-label">
@Html.LabelFor(model => model.Title)
</div>
<div class="editor-field">
@Html.EditorFor(model => model.Title)
@Html.ValidationMessageFor(model => model.Title)
</div>
<div class="editor-label">
@Html.LabelFor(model => model.Credits)
</div>
<div class="editor-field">
@Html.EditorFor(model => model.Credits)
@Html.ValidationMessageFor(model => model.Credits)
</div>
<div class="editor-label">
@Html.LabelFor(model => model.DepartmentID, "Department")
</div>
<div class="editor-field">
@Html.DropDownList("DepartmentID", String.Empty)
@Html.ValidationMessageFor(model => model.DepartmentID)
</div>
<p>
<input type="submit" value="Create" />
</p>
</fieldset>
}
<div>
@Html.ActionLink("Back to List", "Index")
</div>
@section Scripts {
@Scripts.Render("~/bundles/jqueryval")
}
V zobrazeních\Course\Edit.cshtml, Views\Course\Delete.cshtml a Views\Course\Details.cshtml přidejte před pole Název pole číslo kurzu. Protože se jedná o primární klíč, zobrazí se, ale nedá se změnit.
<div class="editor-label">
@Html.LabelFor(model => model.CourseID)
</div>
<div class="editor-field">
@Html.DisplayFor(model => model.CourseID)
</div>
Spusťte stránku Vytvořit (zobrazte stránku Rejstřík kurzu a klikněte na Vytvořit nový) a zadejte data pro nový kurz:
Klikněte na Vytvořit. Zobrazí se stránka Rejstřík kurzu s novým kurzem přidaným do seznamu. Název oddělení v seznamu indexových stránek pochází z navigační vlastnosti, která ukazuje, že relace byla správně navázána.
Spusťte stránku Upravit (zobrazte stránku Rejstřík kurzu a klikněte na Upravit v kurzu).
Změňte data na stránce a klikněte na Uložit. Zobrazí se stránka Index kurzu s aktualizovanými daty kurzu.
Přidání stránky pro úpravy pro instruktory
Při úpravě záznamu instruktora chcete mít možnost aktualizovat zadání instruktora v kanceláři. Entita Instructor
má relaci 1:0 nebo 1 s entitou OfficeAssignment
, což znamená, že musíte zpracovat následující situace:
- Pokud uživatel vymaže přiřazení kanceláře a původně měla hodnotu, musíte entitu
OfficeAssignment
odebrat a odstranit. - Pokud uživatel zadá hodnotu přiřazení kanceláře a původně byla prázdná, musíte vytvořit novou
OfficeAssignment
entitu. - Pokud uživatel změní hodnotu přiřazení kanceláře, musíte změnit hodnotu v existující
OfficeAssignment
entitě.
Otevřete InstructorController.cs a podívejte se na metodu HttpGet
Edit
:
public ActionResult Edit(int id = 0)
{
Instructor instructor = db.Instructors.Find(id);
if (instructor == null)
{
return HttpNotFound();
}
ViewBag.InstructorID = new SelectList(db.OfficeAssignments, "InstructorID", "Location", instructor.InstructorID);
return View(instructor);
}
Vygenerovaný kód tady není to, co chcete. Nastavuje data pro rozevírací seznam, ale to, co potřebujete, je textové pole. Tuto metodu nahraďte následujícím kódem:
public ActionResult Edit(int id)
{
Instructor instructor = db.Instructors
.Include(i => i.OfficeAssignment)
.Where(i => i.InstructorID == id)
.Single();
return View(instructor);
}
Tento kód zahodí ViewBag
příkaz a přidá dychtivé načítání přidružené OfficeAssignment
entity. S metodou Find
nemůžete provádět dychtivé načítání, takže Where
se Single
místo toho používají k výběru instruktora.
Nahraďte metodu HttpPost
Edit
následujícím kódem. které zpracovává aktualizace přiřazení office:
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Edit(int id, FormCollection formCollection)
{
var instructorToUpdate = db.Instructors
.Include(i => i.OfficeAssignment)
.Where(i => i.InstructorID == id)
.Single();
if (TryUpdateModel(instructorToUpdate, "",
new string[] { "LastName", "FirstMidName", "HireDate", "OfficeAssignment" }))
{
try
{
if (String.IsNullOrWhiteSpace(instructorToUpdate.OfficeAssignment.Location))
{
instructorToUpdate.OfficeAssignment = null;
}
db.Entry(instructorToUpdate).State = EntityState.Modified;
db.SaveChanges();
return RedirectToAction("Index");
}
catch (DataException /* dex */)
{
//Log the error (uncomment dex variable name after DataException 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.");
}
}
ViewBag.InstructorID = new SelectList(db.OfficeAssignments, "InstructorID", "Location", id);
return View(instructorToUpdate);
}
Kód provede následující:
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 vHttpGet
Edit
metodě udělali.Aktualizuje načtenou
Instructor
entitu hodnotami z pořadače modelu. Použité přetížení TryUpdateModel umožňuje seznam bezpečných vlastností, které chcete zahrnout. Tím se zabrání nadměrnému účtování, jak je vysvětleno v druhém kurzu.if (TryUpdateModel(instructorToUpdate, "", new string[] { "LastName", "FirstMidName", "HireDate", "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.
V Views\Instructor\Edit.cshtml za div
prvky pro pole Datum přijetí přidejte nové pole pro úpravu umístění kanceláře:
<div class="editor-label">
@Html.LabelFor(model => model.OfficeAssignment.Location)
</div>
<div class="editor-field">
@Html.EditorFor(model => model.OfficeAssignment.Location)
@Html.ValidationMessageFor(model => model.OfficeAssignment.Location)
</div>
Spusťte stránku (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í zadání kurzu na stránku pro úpravy instruktora
Instruktori 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:
Relace mezi entitami Course
a Instructor
entitami je M:N, což znamená, že nemáte přímý přístup k tabulce spojení. Místo toho přidáte a odeberete entity do a z Instructor.Courses
navigační vlastnosti.
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 vybrané. Uživatel může zaškrtnutím nebo zrušením zaškrtnutí políček změnit zadání kurzu. Pokud by byl počet kurzů mnohem větší, pravděpodobně byste chtěli použít jinou metodu prezentace dat v zobrazení, ale k vytvoření nebo odstranění relací byste použili stejnou metodu manipulace s navigačními vlastnostmi.
K zadání dat do zobrazení seznamu zaškrtávacích políček použijete třídu modelu zobrazení. Ve složce ViewModels vytvořte AssignedCourseData.cs a nahraďte stávající kód následujícím kódem:
namespace ContosoUniversity.ViewModels
{
public class AssignedCourseData
{
public int CourseID { get; set; }
public string Title { get; set; }
public bool Assigned { get; set; }
}
}
V InstructorController.cs nahraďte metodu HttpGet
Edit
následujícím kódem. Změny jsou zvýrazněné.
public ActionResult Edit(int id)
{
Instructor instructor = db.Instructors
.Include(i => i.OfficeAssignment)
.Include(i => i.Courses)
.Where(i => i.InstructorID == id)
.Single();
PopulateAssignedCourseData(instructor);
return View(instructor);
}
private void PopulateAssignedCourseData(Instructor instructor)
{
var allCourses = db.Courses;
var instructorCourses = new HashSet<int>(instructor.Courses.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)
});
}
ViewBag.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 kolekce HashSet . Vlastnost je nastavena Assigned
na true
kurzy, které je instruktor přiřazen. Zobrazení použije tuto vlastnost k určení, která zaškrtávací políčka musí být zobrazena jako vybraná. Nakonec se seznam předá zobrazení ve ViewBag
vlastnosti.
Dále přidejte kód, který se spustí, když uživatel klikne na Uložit. Nahraďte metodu HttpPost
Edit
následujícím kódem, který volá novou metodu, která aktualizuje Courses
navigační vlastnost Instructor
entity. Změny jsou zvýrazněné.
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Edit(int id, FormCollection formCollection, string[] selectedCourses)
{
var instructorToUpdate = db.Instructors
.Include(i => i.OfficeAssignment)
.Include(i => i.Courses)
.Where(i => i.InstructorID == id)
.Single();
if (TryUpdateModel(instructorToUpdate, "",
new string[] { "LastName", "FirstMidName", "HireDate", "OfficeAssignment" }))
{
try
{
if (String.IsNullOrWhiteSpace(instructorToUpdate.OfficeAssignment.Location))
{
instructorToUpdate.OfficeAssignment = null;
}
UpdateInstructorCourses(selectedCourses, instructorToUpdate);
db.Entry(instructorToUpdate).State = EntityState.Modified;
db.SaveChanges();
return RedirectToAction("Index");
}
catch (DataException /* dex */)
{
//Log the error (uncomment dex variable name after DataException 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.");
}
}
PopulateAssignedCourseData(instructorToUpdate);
return View(instructorToUpdate);
}
private void UpdateInstructorCourses(string[] selectedCourses, Instructor instructorToUpdate)
{
if (selectedCourses == null)
{
instructorToUpdate.Courses = new List<Course>();
return;
}
var selectedCoursesHS = new HashSet<string>(selectedCourses);
var instructorCourses = new HashSet<int>
(instructorToUpdate.Courses.Select(c => c.CourseID));
foreach (var course in db.Courses)
{
if (selectedCoursesHS.Contains(course.CourseID.ToString()))
{
if (!instructorCourses.Contains(course.CourseID))
{
instructorToUpdate.Courses.Add(course);
}
}
else
{
if (instructorCourses.Contains(course.CourseID))
{
instructorToUpdate.Courses.Remove(course);
}
}
}
}
Vzhledem k tomu, že zobrazení neobsahuje kolekci Course
entit, pořadač modelů nemůže automaticky aktualizovat Courses
navigační vlastnost. Místo použití pořadače modelu k aktualizaci navigační vlastnosti Courses, provedete to v nové UpdateInstructorCourses
metodě. Proto je nutné vlastnost vyloučit Courses
z vazby modelu. To nevyžaduje žádnou změnu kódu, který volá TryUpdateModel , protože používáte přetížení seznamu bezpečných seznamů a Courses
není v seznamu zahrnutí.
Pokud nebyla vybrána žádná zaškrtávací políčka, kód inicializuje UpdateInstructorCourses
Courses
navigační vlastnost s prázdnou kolekcí:
if (selectedCourses == null)
{
instructorToUpdate.Courses = new List<Course>();
return;
}
Kód pak projde všemi kurzy v databázi a zkontroluje jednotlivé kurzy proti kurzům, které jsou aktuálně přiřazené instruktorovi, a ty, které byly vybrány v zobrazení. Pro usnadnění efektivního vyhledávání jsou tyto dvě kolekce uloženy v HashSet
objektech.
Pokud bylo políčko pro kurz zaškrtnuté, ale kurz není v Instructor.Courses
navigační vlastnosti, kurz se přidá do kolekce v navigační vlastnosti.
if (selectedCoursesHS.Contains(course.CourseID.ToString()))
{
if (!instructorCourses.Contains(course.CourseID))
{
instructorToUpdate.Courses.Add(course);
}
}
Pokud nebylo zaškrtnuté políčko pro kurz, ale kurz je v Instructor.Courses
navigační vlastnosti, kurz se z navigační vlastnosti odebere.
else
{
if (instructorCourses.Contains(course.CourseID))
{
instructorToUpdate.Courses.Remove(course);
}
}
V Zobrazení\Instruktor\Edit.cshtml přidejte pole Courses s polem zaškrtávacích políček přidáním následujícího zvýrazněného kódu bezprostředně za div
prvky pole OfficeAssignment
:
@model ContosoUniversity.Models.Instructor
@{
ViewBag.Title = "Edit";
}
<h2>Edit</h2>
@using (Html.BeginForm())
{
@Html.AntiForgeryToken()
@Html.ValidationSummary(true)
<fieldset>
<legend>Instructor</legend>
@Html.HiddenFor(model => model.InstructorID)
<div class="editor-label">
@Html.LabelFor(model => model.LastName)
</div>
<div class="editor-field">
@Html.EditorFor(model => model.LastName)
@Html.ValidationMessageFor(model => model.LastName)
</div>
<div class="editor-label">
@Html.LabelFor(model => model.FirstMidName)
</div>
<div class="editor-field">
@Html.EditorFor(model => model.FirstMidName)
@Html.ValidationMessageFor(model => model.FirstMidName)
</div>
<div class="editor-label">
@Html.LabelFor(model => model.HireDate)
</div>
<div class="editor-field">
@Html.EditorFor(model => model.HireDate)
@Html.ValidationMessageFor(model => model.HireDate)
</div>
<div class="editor-label">
@Html.LabelFor(model => model.OfficeAssignment.Location)
</div>
<div class="editor-field">
@Html.EditorFor(model => model.OfficeAssignment.Location)
@Html.ValidationMessageFor(model => model.OfficeAssignment.Location)
</div>
<div class="editor-field">
<table>
<tr>
@{
int cnt = 0;
List<ContosoUniversity.ViewModels.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>
<p>
<input type="submit" value="Save" />
</p>
</fieldset>
}
<div>
@Html.ActionLink("Back to List", "Index")
</div>
@section Scripts {
@Scripts.Render("~/bundles/jqueryval")
}
Tento kód vytvoří tabulku HTML, která má tři sloupce. V každém sloupci je zaškrtávací políčko následované titulkem, který se skládá z čísla a názvu kurzu. Všechna zaškrtávací políčka mají stejný název ("selectedCourses"), která informuje pořadač modelů, že se mají považovat za skupinu. Atribut value
každého zaškrtávacího CourseID.
políčka je nastaven na hodnotu Při publikování stránky, pořadač modelu předá matici kontroleru, který se skládá z CourseID
hodnot pouze pro zaškrtávací políčka, která jsou zaškrtnutá.
Po počátečním vykreslení zaškrtávacích políček mají kurzy přiřazené instruktorovi checked
atributy, které je vybere (zobrazí se zaškrtnuté).
Po změně zadání kurzu budete chtít být schopni ověřit změny, když se web vrátí na Index
stránku. Proto musíte do tabulky na této stránce přidat sloupec. V takovém případě nemusíte objekt používat ViewBag
, protože informace, které chcete zobrazit, už jsou v Courses
navigační vlastnosti Instructor
entity, kterou předáváte na stránku jako model.
V views\Instructor\Index.cshtml přidejte nadpis Courses bezprostředně za nadpis Office , jak je znázorněno v následujícím příkladu:
<tr>
<th></th>
<th>Last Name</th>
<th>First Name</th>
<th>Hire Date</th>
<th>Office</th>
<th>Courses</th>
</tr>
Potom přidejte novou buňku podrobností bezprostředně za buňku s podrobnostmi o poloze kanceláře:
@model ContosoUniversity.ViewModels.InstructorIndexData
@{
ViewBag.Title = "Instructors";
}
<h2>Instructors</h2>
<p>
@Html.ActionLink("Create New", "Create")
</p>
<table>
<tr>
<th></th>
<th>Last Name</th>
<th>First Name</th>
<th>Hire Date</th>
<th>Office</th>
<th>Courses</th>
</tr>
@foreach (var item in Model.Instructors)
{
string selectedRow = "";
if (item.InstructorID == ViewBag.InstructorID)
{
selectedRow = "selectedrow";
}
<tr class="@selectedRow" valign="top">
<td>
@Html.ActionLink("Select", "Index", new { id = item.InstructorID }) |
@Html.ActionLink("Edit", "Edit", new { id = item.InstructorID }) |
@Html.ActionLink("Details", "Details", new { id = item.InstructorID }) |
@Html.ActionLink("Delete", "Delete", new { id = item.InstructorID })
</td>
<td>
@item.LastName
</td>
<td>
@item.FirstMidName
</td>
<td>
@String.Format("{0:d}", item.HireDate)
</td>
<td>
@if (item.OfficeAssignment != null)
{
@item.OfficeAssignment.Location
}
</td>
<td>
@{
foreach (var course in item.Courses)
{
@course.CourseID @: @course.Title <br />
}
}
</td>
</tr>
}
</table>
@if (Model.Courses != null)
{
<h3>Courses Taught by Selected Instructor</h3>
<table>
<tr>
<th></th>
<th>ID</th>
<th>Title</th>
<th>Department</th>
</tr>
@foreach (var item in Model.Courses)
{
string selectedRow = "";
if (item.CourseID == ViewBag.CourseID)
{
selectedRow = "selectedrow";
}
<tr class="@selectedRow">
<td>
@Html.ActionLink("Select", "Index", new { courseID = item.CourseID })
</td>
<td>
@item.CourseID
</td>
<td>
@item.Title
</td>
<td>
@item.Department.Name
</td>
</tr>
}
</table>
}
@if (Model.Enrollments != null)
{
<h3>Students Enrolled in Selected Course</h3>
<table>
<tr>
<th>Name</th>
<th>Grade</th>
</tr>
@foreach (var item in Model.Enrollments)
{
<tr>
<td>
@item.Student.FullName
</td>
<td>
@Html.DisplayFor(modelItem => item.Grade)
</td>
</tr>
}
</table>
}
Spuštěním stránky indexu instruktora zobrazte kurzy přiřazené jednotlivým instruktorům:
Kliknutím na Upravit u instruktora zobrazíte stránku Upravit.
Změňte některá zadání kurzu a klikněte na Uložit. Provedené změny se projeví na stránce Rejstříku.
Poznámka: Přístup k úpravě dat kurzu instruktora funguje dobře, pokud existuje omezený počet kurzů. U kolekcí, které jsou mnohem větší, by se vyžadovalo jiné uživatelské rozhraní a jiná metoda aktualizace.
Aktualizace metody Delete
Změňte kód v metodě HttpPost Delete tak, aby se po odstranění instruktora odstranil záznam přiřazení office (pokud existuje):
[HttpPost, ActionName("Delete")]
[ValidateAntiForgeryToken]
public ActionResult DeleteConfirmed(int id)
{
Instructor instructor = db.Instructors
.Include(i => i.OfficeAssignment)
.Where(i => i.InstructorID == id)
.Single();
instructor.OfficeAssignment = null;
db.Instructors.Remove(instructor);
db.SaveChanges();
return RedirectToAction("Index");
}
Pokud se pokusíte odstranit instruktora, který je přiřazen k oddělení jako správce, zobrazí se chyba referenční integrity. V aktuální verzi tohoto kurzu najdete další kód, který automaticky odebere instruktora z libovolného oddělení, ve kterém je instruktor přiřazený jako správce.
Shrnutí
Dokončili jste tento úvod do práce se souvisejícími daty. Zatím jste v těchto kurzech provedli celou řadu operací CRUD, ale neřešili jste problémy se souběžností. V dalším kurzu se seznámíte s tématem souběžnosti, vysvětlíme možnosti pro jeho zpracování a přidáte zpracování souběžnosti do kódu CRUD, který jste už napsali pro jeden typ entity.
Odkazy na další prostředky Entity Framework najdete na konci posledního kurzu v této sérii.