Обновление связанных данных с помощью Entity Framework в приложении MVC ASP.NET (6 из 10)
Пример веб-приложения Университета Contoso демонстрирует создание ASP.NET приложений MVC 4 с помощью Entity Framework 5 Code First и Visual Studio 2012. Сведения о серии руководств см. в первом руководстве серии.
Примечание
Если у вас возникла проблема, которую не удается устранить, скачайте завершенную главу и попробуйте воспроизвести проблему. Как правило, решение проблемы можно найти, сравнив код с готовым кодом. Сведения о некоторых распространенных ошибках и способах их устранения см. в статье Ошибки и обходные пути.
В предыдущем руководстве вы отображали связанные данные; В этом руководстве вы обновите связанные данные. Для большинства связей это можно сделать, обновив соответствующие поля внешнего ключа. Для связей "многие ко многим" Entity Framework не предоставляет таблицу соединения напрямую, поэтому необходимо явным образом добавлять сущности в соответствующие свойства навигации и удалять их из нее.
На следующих рисунках изображены страницы, с которыми вы будете работать.
Настройка страниц создания и редактирования для курсов
Создаваемая сущность курса должна иметь связь с существующей кафедрой. Чтобы упростить эту задачу, шаблонный код включает методы контроллеров, а также представления "Create" (Создание) и "Edit" (Редактирование) с раскрывающимся списком для выбора кафедры. Раскрывающийся список задает свойство внешнего ключа Course.DepartmentID
, и это все, что нужно Entity Framework для загрузки свойства навигации Department
с соответствующей сущностью Department
. Вы будете использовать этот шаблонный код, немного его изменив, чтобы добавить обработку ошибок и сортировку раскрывающегося списка.
В файле CourseController.cs удалите четыре Edit
метода и и Create
замените их следующим кодом:
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);
}
Метод PopulateDepartmentsDropDownList
получает список всех отделов, отсортированных по имени, создает SelectList
коллекцию для раскрывающегося списка и передает коллекцию в представление в свойстве ViewBag
. Этот метод принимает необязательный параметр selectedDepartment
, позволяющий вызывающему коду указать элемент, который будет выбран при отрисовке раскрывающегося списка. Представление передаст имя DepartmentID
вспомогательному DropDownList
объекту, а вспомогателям будет известно, что он будет искать в ViewBag
объекте именованный SelectList
DepartmentID
объект .
Метод HttpGet
Create
вызывает PopulateDepartmentsDropDownList
метод без задания выбранного элемента, так как для нового курса кафедра еще не создана:
public ActionResult Create()
{
PopulateDepartmentsDropDownList();
return View();
}
Метод HttpGet
Edit
задает выбранный элемент на основе идентификатора отдела, который уже назначен редактируемому курсу:
public ActionResult Edit(int id)
{
Course course = db.Courses.Find(id);
PopulateDepartmentsDropDownList(course.DepartmentID);
return View(course);
}
Методы HttpPost
для обоих Create
, а Edit
также включают код, который задает выбранный элемент при повторном воспроизведении страницы после ошибки:
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);
Этот код гарантирует, что при повторном воспроизведении страницы для отображения сообщения об ошибке выбранный отдел остается выбранным.
В views\Course\Create.cshtml добавьте выделенный код, чтобы создать новое поле номера курса перед полем Title . Как описано в предыдущем руководстве, поля первичного ключа по умолчанию не сформированы, но этот первичный ключ имеет смысл, поэтому пользователь должен иметь возможность ввести значение ключа.
@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")
}
В views\Course\Edit.cshtml, Views\Course\Delete.cshtml и Views\Course\Details.cshtml добавьте поле номера курса перед полем Title . Так как это первичный ключ, он отображается, но его нельзя изменить.
<div class="editor-label">
@Html.LabelFor(model => model.CourseID)
</div>
<div class="editor-field">
@Html.DisplayFor(model => model.CourseID)
</div>
Запустите страницу Создание (отобразите страницу Индекс курса и щелкните Создать) и введите данные для нового курса:
Нажмите кнопку Создать. Отобразится страница "Индекс курса" с новым курсом, добавленным в список. Название кафедры в списке страницы индекса поступает из свойства навигации, показывая, что связь установлена правильно.
Запустите страницу Правка (отобразите страницу Индекс курса и щелкните Изменить для курса).
Измените данные на странице и нажмите кнопку Save (Сохранить). Отобразится страница "Индекс курса" с обновленными данными курса.
Добавление страницы редактирования для преподавателей
При редактировании записи преподавателя может потребоваться обновить назначенный преподавателю кабинет. Сущность Instructor
имеет связь "один к нулю или одному" с сущностью OfficeAssignment
, что означает, что необходимо обрабатывать следующие ситуации:
- Если пользователь очищает назначение office и изначально имело значение, необходимо удалить и удалить
OfficeAssignment
сущность. - Если пользователь вводит значение назначения Office, которое изначально было пустым, необходимо создать новую
OfficeAssignment
сущность. - Если пользователь изменяет значение назначения office, необходимо изменить значение в существующей
OfficeAssignment
сущности.
Откройте файл InstructorController.cs и просмотрите 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);
}
Шаблонный код здесь не является тем, что вы хотите. Он настраивает данные для раскрывающегося списка, но вам нужно текстовое поле. Замените этот метод следующим кодом:
public ActionResult Edit(int id)
{
Instructor instructor = db.Instructors
.Include(i => i.OfficeAssignment)
.Where(i => i.InstructorID == id)
.Single();
return View(instructor);
}
Этот код удаляет инструкцию ViewBag
и добавляет неотложную загрузку для связанной OfficeAssignment
сущности. Вы не можете выполнить неотложную загрузку Find
с помощью метода , поэтому Where
вместо этого используются методы и Single
для выбора инструктора.
Замените HttpPost
Edit
метод следующим кодом. который обрабатывает обновления назначений 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);
}
Этот код выполняет следующее:
Получает текущую сущность
Instructor
из базы данных, используя безотложную загрузку для свойства навигацииOfficeAssignment
. Это то же самое, что и в методеHttpGet
Edit
.Обновляет извлеченную сущность
Instructor
, используя значения из связывателя модели. Используемая перегрузка TryUpdateModel позволяет добавить в список надежных свойств, которые вы хотите включить. Это предотвращает чрезмерную публикацию, как описано во втором руководстве.if (TryUpdateModel(instructorToUpdate, "", new string[] { "LastName", "FirstMidName", "HireDate", "OfficeAssignment" }))
Если расположение кабинета отсутствует, задает для свойства
Instructor.OfficeAssignment
значение NULL, что приводит к удалению связанной строки в таблицеOfficeAssignment
.if (String.IsNullOrWhiteSpace(instructorToUpdate.OfficeAssignment.Location)) { instructorToUpdate.OfficeAssignment = null; }
Сохраняет изменения в базу данных.
В файле Views\Instructor\Edit.cshtml после 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>
Запустите страницу (выберите вкладку Преподаватели и нажмите кнопку Изменить для преподавателя). Измените значение Office Location (Расположение кабинета) и нажмите кнопку Save (Сохранить).
Добавление заданий курса на страницу редактирования преподавателя
Преподаватели могут вести любое число курсов. Теперь вы улучшите страницу редактирования преподавателя, добавив возможность изменять назначения курсов с помощью группы флажков, как показано на следующем снимке экрана:
Связь между Course
сущностями и Instructor
является "многие ко многим", что означает, что у вас нет прямого доступа к таблице соединения. Вместо этого вы будете добавлять сущности в свойство навигации и удалять их из него Instructor.Courses
.
Пользовательский интерфейс, позволяющий изменить назначенные для преподавателя курсы, представляет собой группу флажков. Отображается флажок для каждого курса в базе данных, а флажки для курсов, назначенных данному преподавателю, установлены. Пользователь может устанавливать и снимать флажки, изменяя назначения курсов. Если число курсов было гораздо больше, вам, вероятно, потребуется использовать другой метод представления данных в представлении, но вы бы использовали тот же метод управления свойствами навигации для создания или удаления связей.
Чтобы предоставить данные в представлении для списка флажков, нужно использовать класс модели представления. Создайте файл AssignedCourseData.cs в папке ViewModels и замените существующий код следующим кодом:
namespace ContosoUniversity.ViewModels
{
public class AssignedCourseData
{
public int CourseID { get; set; }
public string Title { get; set; }
public bool Assigned { get; set; }
}
}
В Файле InstructorController.cs замените HttpGet
Edit
метод следующим кодом. Изменения выделены.
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;
}
Код добавляет безотложную загрузку для свойства навигации Courses
и вызывает новый метод PopulateAssignedCourseData
для предоставления сведений массиву флажков с помощью класса модели представления AssignedCourseData
.
Код в методе PopulateAssignedCourseData
считывает все сущности Course
, чтобы загрузить список курсов, используя класс модели представления. Для каждого курса код проверяет, существует ли этот курс в свойстве навигации Courses
преподавателя. Чтобы обеспечить эффективный поиск при проверке назначения курса инструктору, курсы, назначенные преподавателю, помещаются в коллекцию HashSet . Свойству Assigned
присваивается значение true
для курсов, назначенных инструктору. Представление будет использовать это свойство, чтобы определить, какие флажки нужно отображать как выбранные. Наконец, список передается в представление в свойстве ViewBag
.
Добавьте код, выполняемый, когда пользователь нажимает кнопку Save (Сохранить). Замените HttpPost
Edit
метод приведенным ниже кодом, который вызывает новый метод, обновляющий Courses
свойство навигации сущности Instructor
. Изменения выделены.
[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);
}
}
}
}
Так как представление не содержит коллекцию сущностей Course
, связыватель модели не может автоматически обновить свойство навигации Courses
. Вместо использования связывателя модели для обновления свойства навигации Courses это можно сделать в новом UpdateInstructorCourses
методе. Поэтому нужно исключить свойство Courses
из привязки модели. Для этого не требуется вносить изменения в код, вызывающий TryUpdateModel , так как вы используете перегрузку списка безопасных файлов и Courses
не входите в список включения.
Если проверка поля не были выбраны, код в инициализирует UpdateInstructorCourses
свойство навигации Courses
с пустой коллекцией:
if (selectedCourses == null)
{
instructorToUpdate.Courses = new List<Course>();
return;
}
После этого код в цикле проходит по всем курсам в базе данных и сравнивает каждый из них с теми, которые сейчас назначены преподавателю, в противоположность тем, которые были выбраны в представлении. Чтобы упростить эффективную подстановку, последние две коллекции хранятся в объектах HashSet
.
Если флажок для курса был установлен, но курс отсутствует в свойстве навигации Instructor.Courses
, этот курс добавляется в коллекцию в свойстве навигации.
if (selectedCoursesHS.Contains(course.CourseID.ToString()))
{
if (!instructorCourses.Contains(course.CourseID))
{
instructorToUpdate.Courses.Add(course);
}
}
Если флажок для курса не был установлен, но курс присутствует в свойстве навигации Instructor.Courses
, этот курс удаляется из свойства навигации.
else
{
if (instructorCourses.Contains(course.CourseID))
{
instructorToUpdate.Courses.Remove(course);
}
}
В Views\Instructor\Edit.cshtml добавьте поле Courses с массивом полей проверка, добавив следующий выделенный код сразу после div
элементов 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")
}
Этот код создает таблицу HTML с тремя столбцами. Каждый столбец содержит флажок, за которым идет заголовок с номером и названием курса. Все поля проверка имеют одинаковое имя ("selectedCourses"), которое сообщает связыватель модели о том, что они должны рассматриваться как группа. Атрибуту value
каждого поля проверка задано значение CourseID.
При публикации страницы связыватель модели передает массив контроллеру, который состоит из значений CourseID
только для выбранных проверка полей.
Когда поля проверка изначально отображаются, те, которые предназначены для курсов, назначенных преподавателю, имеют checked
атрибуты, которые выбирают их (отображает их с флажками).
После изменения заданий курса вы хотите иметь возможность проверить изменения при возвращении сайта на страницу Index
. Поэтому необходимо добавить столбец в таблицу на этой странице. В этом случае вам не нужно использовать ViewBag
объект , так как информация, которую вы хотите отобразить, уже находится в свойстве Courses
навигации сущности Instructor
, передаваемой на страницу в качестве модели.
В views\Instructor\Index.cshtml добавьте заголовок Courses сразу после заголовка Office , как показано в следующем примере:
<tr>
<th></th>
<th>Last Name</th>
<th>First Name</th>
<th>Hire Date</th>
<th>Office</th>
<th>Courses</th>
</tr>
Затем добавьте новую ячейку сведений сразу после ячейки сведений о расположении офиса:
@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>
}
Запустите страницу Индекс преподавателя , чтобы просмотреть курсы, назначенные каждому преподавателю:
Нажмите кнопку Изменить для преподавателя, чтобы открыть страницу Правка.
Измените некоторые задания курсов и нажмите кнопку Сохранить. Вносимые вами изменения отражаются на странице индекса.
Примечание. Подход, принятый для редактирования данных курса преподавателя, хорошо работает при ограниченном количестве курсов. Для коллекций большего размера следовало бы применять другой пользовательский интерфейс и другой метод обновления.
Обновление метода Delete
Измените код в методе HttpPost Delete, чтобы при удалении преподавателя была удалена запись о назначении офиса (если она есть):
[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");
}
При попытке удалить преподавателя, назначенного отделу в качестве администратора, вы получите ошибку целостности данных. В текущей версии этого руководства приведен дополнительный код, который автоматически удаляет преподавателя из любого отдела, в котором инструктор назначен администратором.
Итоги
Вы завершили работу со связанными данными. До сих пор в этих руководствах вы выполнили полный спектр операций CRUD, но не рассмотрели проблемы с параллелизмом. В следующем руководстве рассматривается тема параллелизма, описываются варианты его обработки и добавляется обработка параллелизма в код CRUD, который вы уже написали для одного типа сущности.
Ссылки на другие ресурсы Entity Framework можно найти в конце последнего руководства в этой серии.
Обратная связь
https://aka.ms/ContentUserFeedback.
Ожидается в ближайшее время: в течение 2024 года мы постепенно откажемся от GitHub Issues как механизма обратной связи для контента и заменим его новой системой обратной связи. Дополнительные сведения см. в разделеОтправить и просмотреть отзыв по