C# – Update related data – ASP.NET MVC with EF Core
After reading complex the data, it is time to be able to update it. This video fills the following points from the ASP.NET MVC tutorial:
- Customize Courses pages
- Add Instructors Edit page
- Add courses to Edit page
- Update Delete page
- Add office location and courses to Create page
I liked explicitly the generation of the checkboxes, making a relation to a corresponding table:

This is the html-razor syntax for the generation:
<div class="form-group">
<table>
<tr>
@{
List<ContosoUniversity.Models.SchoolViewModels.AssignedCourseData> courses = ViewBag.Courses;
foreach (var course in courses)
{
@:</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>
In the InstructorController.cs the Edit POST and GET methods look quite nicely as well – reading and writing from multiple database tables correctly:
[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(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;
}
UpdateInstructorCourses(selectedCourses, instructorToUpdate);
try
{
await _context.SaveChangesAsync();
}
catch (DbUpdateException)
{
ModelState.AddModelError("", "Unable to save changes. Please restart!");
}
return RedirectToAction(nameof(Index));
}
UpdateInstructorCourses(selectedCourses, instructorToUpdate);
PopulateAssignedCourseData(instructorToUpdate);
return View(instructorToUpdate);
}
// GET: Instructors/Edit/5
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);
}
The additional methods PopulateAssignedCourseData() and UpdateInstructorCourses() do what their names say – pretty much rendering relevant course data implementing Update functionailty for the courses:
private void UpdateInstructorCourses(string[] selectedCourses, Instructor instructorToUpdate)
{
if (selectedCourses == null)
{
instructorToUpdate.CourseAssignments = new List<CourseAssignment>();
return;
}
var selectedCoursesNotNull = new HashSet<string>(selectedCourses);
var instructorCourses = new HashSet<int>
(instructorToUpdate.CourseAssignments.Select(c => c.Course.CourseId));
foreach (var course in _context.Courses)
{
if (selectedCoursesNotNull.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);
}
}
}
}
The Course.cs class used in the method below is in the Models folder:
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;
}
Everything is available in GitHub – https://github.com/Vitosh/ASP/tree/master/EFCoreAsp.NetMvcWebApp/ContosoUniversity007
Enjoy! 🙂