Anteckning
Åtkomst till den här sidan kräver auktorisering. Du kan prova att logga in eller ändra kataloger.
Åtkomst till den här sidan kräver auktorisering. Du kan prova att ändra kataloger.
Av Tom Dykstra, Jon P Smith och Rick Anderson
Contoso University-webbappen visar hur du skapar webbappar för Razor Pages med hjälp av EF Core och Visual Studio. Information om självstudieserien finns i den första självstudien.
Om du stöter på problem som du inte kan lösa, ladda ner den färdiga appen och jämför den koden med den du skapade när du följde handledningen.
Den här handledningen visar hur du uppdaterar relaterad data. Följande bilder visar några av de slutförda sidorna.
              
              
              
              
            
Uppdatera kurssidorna för att skapa och redigera kurser
Den genererade koden för sidorna Kursskapande och redigering har en avdelningsrullgardinsmeny som visar DepartmentID, en int. Listrutan bör visa avdelningsnamnet, så båda dessa sidor behöver en lista med avdelningsnamn. Om du vill ange den listan använder du en basklass för sidorna Skapa och redigera.
Skapa en basklass för Kursskapa och redigera
Skapa en Pages/Courses/DepartmentNamePageModel.cs fil med följande kod:
using ContosoUniversity.Data;
using ContosoUniversity.Models;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.AspNetCore.Mvc.Rendering;
using Microsoft.EntityFrameworkCore;
using System.Linq;
namespace ContosoUniversity.Pages.Courses
{
    public class DepartmentNamePageModel : PageModel
    {
        public SelectList DepartmentNameSL { get; set; }
        public void PopulateDepartmentsDropDownList(SchoolContext _context,
            object selectedDepartment = null)
        {
            var departmentsQuery = from d in _context.Departments
                                   orderby d.Name // Sort by name.
                                   select d;
            DepartmentNameSL = new SelectList(departmentsQuery.AsNoTracking(),
                nameof(Department.DepartmentID),
                nameof(Department.Name),
                selectedDepartment);
        }
    }
}
Föregående kod skapar en SelectList för att innehålla listan över avdelningsnamn. Parametern selectedDepartment gör att den anropande koden kan ange det objekt som ska väljas när listrutan återges. Men när du använder hjälpverktyget Välj tagg med asp-forbestäms det valda objektet av modellegenskapsvärdet (till exempel Course.DepartmentID), inte av parametern selectedDepartment .
Viktigt!
När du använder hjälpverktyget Välj tagg med asp-for="Course.DepartmentID"bestäms det valda alternativet automatiskt av Course.DepartmentIDvärdet för . Parametern selectedDepartment som skickas till Konstruktorn SelectList ignoreras i det här scenariot.
Klasserna Skapa och redigera sidmodell härleds från DepartmentNamePageModel.
Uppdatera sidmodellen för kursskapande
En kurs tilldelas till en avdelning. Basklassen för sidorna Skapa och redigera innehåller en SelectList för att välja avdelning. Listrutan som använder SelectList anger Course.DepartmentID egenskapen främmande nyckel (FK). 
              EF Core använder FK:n Course.DepartmentID för att infoga navigeringsegenskap Department.
              
              
            
Uppdatera Pages/Courses/Create.cshtml.cs med följande kod:
using ContosoUniversity.Models;
using Microsoft.AspNetCore.Mvc;
using System.Threading.Tasks;
namespace ContosoUniversity.Pages.Courses
{
    public class CreateModel : DepartmentNamePageModel
    {
        private readonly ContosoUniversity.Data.SchoolContext _context;
        public CreateModel(ContosoUniversity.Data.SchoolContext context)
        {
            _context = context;
        }
        public IActionResult OnGet()
        {
            PopulateDepartmentsDropDownList(_context);
            return Page();
        }
        [BindProperty]
        public Course Course { get; set; }
        public async Task<IActionResult> OnPostAsync()
        {
            var emptyCourse = new Course();
            if (await TryUpdateModelAsync<Course>(
                 emptyCourse,
                 "course",   // Prefix for form value.
                 s => s.CourseID, s => s.DepartmentID, s => s.Title, s => s.Credits))
            {
                _context.Courses.Add(emptyCourse);
                await _context.SaveChangesAsync();
                return RedirectToPage("./Index");
            }
            // Repopulate departments dropdown. emptyCourse.DepartmentID determines the selected item.
            PopulateDepartmentsDropDownList(_context, emptyCourse.DepartmentID);
            return Page();
        }
      }
}
Om du vill se kodkommentar översatta till andra språk än engelska kan du meddela oss i det här GitHub-diskussionsproblemet.
Föregående kod:
- Härleds från 
DepartmentNamePageModel. - Används TryUpdateModelAsync för att förhindra överpublicering.
 - Tar bort 
ViewData["DepartmentID"].DepartmentNameSLSelectListär en starkt typad modell och kommer att användas av sidan Razor. Starkt skrivna modeller föredras framför svagt skrivna. Mer information finns i Svagt inskrivna data (ViewData och ViewBag). 
Uppdatera Kursskapandets sida Razor
Uppdatera Pages/Courses/Create.cshtml med följande kod:
@page
@model ContosoUniversity.Pages.Courses.CreateModel
@{
    ViewData["Title"] = "Create Course";
}
<h2>Create</h2>
<h4>Course</h4>
<hr />
<div class="row">
    <div class="col-md-4">
        <form method="post">
            <div asp-validation-summary="ModelOnly" class="text-danger"></div>
            <div class="form-group">
                <label asp-for="Course.CourseID" class="control-label"></label>
                <input asp-for="Course.CourseID" class="form-control" />
                <span asp-validation-for="Course.CourseID" class="text-danger"></span>
            </div>
            <div class="form-group">
                <label asp-for="Course.Title" class="control-label"></label>
                <input asp-for="Course.Title" class="form-control" />
                <span asp-validation-for="Course.Title" class="text-danger"></span>
            </div>
            <div class="form-group">
                <label asp-for="Course.Credits" class="control-label"></label>
                <input asp-for="Course.Credits" class="form-control" />
                <span asp-validation-for="Course.Credits" class="text-danger"></span>
            </div>
            <div class="form-group">
                <label asp-for="Course.Department" class="control-label"></label>
                <select asp-for="Course.DepartmentID" class="form-control"
                        asp-items="@Model.DepartmentNameSL">
                    <option value="">-- Select Department --</option>
                </select>
                <span asp-validation-for="Course.DepartmentID" class="text-danger" />
            </div>
            <div class="form-group">
                <input type="submit" value="Create" class="btn btn-primary" />
            </div>
        </form>
    </div>
</div>
<div>
    <a asp-page="Index">Back to List</a>
</div>
@section Scripts {
    @{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
}
Föregående kod gör följande ändringar:
- Ändrar bildtexten från DepartmentID till Department.
 - 
              
"ViewBag.DepartmentID"Ersätter medDepartmentNameSL(från basklassen). - Lägger till alternativet "Välj avdelning". Den här ändringen återger "Välj avdelning" i listrutan när ingen avdelning har valts ännu, i stället för den första avdelningen.
 - Lägger till ett valideringsmeddelande när avdelningen inte har valts.
 
Sidan Razor använder hjälpen Välj tagg:
<div class="form-group">
    <label asp-for="Course.Department" class="control-label"></label>
    <select asp-for="Course.DepartmentID" class="form-control"
            asp-items="@Model.DepartmentNameSL">
        <option value="">-- Select Department --</option>
    </select>
    <span asp-validation-for="Course.DepartmentID" class="text-danger" />
</div>
Testa Skapa-sidan. På sidan Skapa visas avdelningsnamnet i stället för avdelnings-ID:t.
Uppdatera kursredigeringssidemodellen
Uppdatera Pages/Courses/Edit.cshtml.cs med följande kod:
using ContosoUniversity.Models;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using System.Threading.Tasks;
namespace ContosoUniversity.Pages.Courses
{
    public class EditModel : DepartmentNamePageModel
    {
        private readonly ContosoUniversity.Data.SchoolContext _context;
        public EditModel(ContosoUniversity.Data.SchoolContext context)
        {
            _context = context;
        }
        [BindProperty]
        public Course Course { get; set; }
        public async Task<IActionResult> OnGetAsync(int? id)
        {
            if (id == null)
            {
                return NotFound();
            }
            Course = await _context.Courses
                .Include(c => c.Department).FirstOrDefaultAsync(m => m.CourseID == id);
            if (Course == null)
            {
                return NotFound();
            }
            // Populate departments dropdown. Course.DepartmentID determines the selected item.
            PopulateDepartmentsDropDownList(_context, Course.DepartmentID);
            return Page();
        }
        public async Task<IActionResult> OnPostAsync(int? id)
        {
            if (id == null)
            {
                return NotFound();
            }
            var courseToUpdate = await _context.Courses.FindAsync(id);
            if (courseToUpdate == null)
            {
                return NotFound();
            }
            if (await TryUpdateModelAsync<Course>(
                 courseToUpdate,
                 "course",   // Prefix for form value.
                   c => c.Credits, c => c.DepartmentID, c => c.Title))
            {
                await _context.SaveChangesAsync();
                return RedirectToPage("./Index");
            }
            // Repopulate departments dropdown. courseToUpdate.DepartmentID determines the selected item.
            PopulateDepartmentsDropDownList(_context, courseToUpdate.DepartmentID);
            return Page();
        }       
    }
}
Ändringarna liknar dem som gjordes i Skapa sidmodellen. I föregående kod överför PopulateDepartmentsDropDownList avdelnings-ID:t. När du använder hjälpverktyget Välj tagg med asp-for="Course.DepartmentID"bestäms det markerade objektet i listrutan av Course.DepartmentIDvärdet för , inte av parametern selectedDepartment som skickas till konstruktorn SelectList.
Uppdatera sidan Kursredigering Razor
Uppdatera Pages/Courses/Edit.cshtml med följande kod:
@page
@model ContosoUniversity.Pages.Courses.EditModel
@{
    ViewData["Title"] = "Edit";
}
<h2>Edit</h2>
<h4>Course</h4>
<hr />
<div class="row">
    <div class="col-md-4">
        <form method="post">
            <div asp-validation-summary="ModelOnly" class="text-danger"></div>
            <input type="hidden" asp-for="Course.CourseID" />
            <div class="form-group">
                <label asp-for="Course.CourseID" class="control-label"></label>
                <div>@Html.DisplayFor(model => model.Course.CourseID)</div>
            </div>
            <div class="form-group">
                <label asp-for="Course.Title" class="control-label"></label>
                <input asp-for="Course.Title" class="form-control" />
                <span asp-validation-for="Course.Title" class="text-danger"></span>
            </div>
            <div class="form-group">
                <label asp-for="Course.Credits" class="control-label"></label>
                <input asp-for="Course.Credits" class="form-control" />
                <span asp-validation-for="Course.Credits" class="text-danger"></span>
            </div>
            <div class="form-group">
                <label asp-for="Course.Department" class="control-label"></label>
                <select asp-for="Course.DepartmentID" class="form-control" 
                        asp-items="@Model.DepartmentNameSL"></select>
                <span asp-validation-for="Course.DepartmentID" class="text-danger"></span>
            </div>
            <div class="form-group">
                <input type="submit" value="Save" class="btn btn-primary" />
            </div>
        </form>
    </div>
</div>
<div>
    <a asp-page="./Index">Back to List</a>
</div>
@section Scripts {
    @{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
}
Föregående kod gör följande ändringar:
- Visar kurs-ID. Vanligtvis visas inte primärnyckeln (PK) för en entitet. PK:er är vanligtvis meningslösa för användarna. I det här fallet är PK:t kursnumret.
 - Ändrar beskrivningen för listrutan Avdelning från DepartmentID till Avdelning.
 - 
              
"ViewBag.DepartmentID"Ersätter medDepartmentNameSL, som finns i basklassen. 
Sidan innehåller ett dolt fält (<input type="hidden">) för kursnumret. Att lägga till en <label> tag helper med asp-for="Course.CourseID" eliminerar inte behovet av det dolda fältet. 
              <input type="hidden"> krävs för att kursnumret ska inkluderas i de publicerade data när användaren väljer Spara.
Uppdatera kurssidans modeller
AsNoTracking kan förbättra prestanda när spårning inte krävs.
Uppdatera Pages/Courses/Delete.cshtml.cs och Pages/Courses/Details.cshtml.cs genom att lägga AsNoTracking till OnGetAsync i metoderna:
public async Task<IActionResult> OnGetAsync(int? id)
{
    if (id == null)
    {
        return NotFound();
    }
    Course = await _context.Courses
        .AsNoTracking()
        .Include(c => c.Department)
        .FirstOrDefaultAsync(m => m.CourseID == id);
    if (Course == null)
    {
        return NotFound();
    }
    return Page();
}
Uppdatera kurs Razor-sidorna
Uppdatera Pages/Courses/Delete.cshtml med följande kod:
@page
@model ContosoUniversity.Pages.Courses.DeleteModel
@{
    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.Course.CourseID)
        </dt>
        <dd class="col-sm-10">
            @Html.DisplayFor(model => model.Course.CourseID)
        </dd>
        <dt class="col-sm-2">
            @Html.DisplayNameFor(model => model.Course.Title)
        </dt>
        <dd class="col-sm-10">
            @Html.DisplayFor(model => model.Course.Title)
        </dd>
        <dt class="col-sm-2">
            @Html.DisplayNameFor(model => model.Course.Credits)
        </dt>
        <dd class="col-sm-10">
            @Html.DisplayFor(model => model.Course.Credits)
        </dd>
        <dt class="col-sm-2">
            @Html.DisplayNameFor(model => model.Course.Department)
        </dt>
        <dd class="col-sm-10">
            @Html.DisplayFor(model => model.Course.Department.Name)
        </dd>
    </dl>
    
    <form method="post">
        <input type="hidden" asp-for="Course.CourseID" />
        <input type="submit" value="Delete" class="btn btn-danger" /> |
        <a asp-page="./Index">Back to List</a>
    </form>
</div>
Gör samma ändringar på sidan Information.
@page
@model ContosoUniversity.Pages.Courses.DetailsModel
@{
    ViewData["Title"] = "Details";
}
<h2>Details</h2>
<div>
    <h4>Course</h4>
    <hr />
    <dl class="row">
        <dt class="col-sm-2">
            @Html.DisplayNameFor(model => model.Course.CourseID)
        </dt>
        <dd class="col-sm-10">
            @Html.DisplayFor(model => model.Course.CourseID)
        </dd>
        <dt class="col-sm-2">
            @Html.DisplayNameFor(model => model.Course.Title)
        </dt>
        <dd class="col-sm-10">
            @Html.DisplayFor(model => model.Course.Title)
        </dd>
        <dt class="col-sm-2">
            @Html.DisplayNameFor(model => model.Course.Credits)
        </dt>
        <dd class="col-sm-10">
            @Html.DisplayFor(model => model.Course.Credits)
        </dd>
        <dt class="col-sm-2">
            @Html.DisplayNameFor(model => model.Course.Department)
        </dt>
        <dd class="col-sm-10">
            @Html.DisplayFor(model => model.Course.Department.Name)
        </dd>
    </dl>
</div>
<div>
    <a asp-page="./Edit" asp-route-id="@Model.Course.CourseID">Edit</a> |
    <a asp-page="./Index">Back to List</a>
</div>
Testa kursens sidor
Testa skapa, redigera, visa information och ta bort-sidorna.
Uppdatera instruktören Skapa och redigera sidor
Instruktörer kan undervisa valfritt antal kurser. Följande bild visar instruktörens redigeringssida med en uppsättning av kurser i kryssrutor.
              
              
            
Kryssrutorna gör det möjligt att ändra kurser som en lärare har tilldelats till. En kryssruta visas för varje kurs i databasen. Kurser som instruktören är tilldelad till väljs. Användaren kan markera eller avmarkera kryssrutor för att ändra kurstilldelningar. Om antalet kurser var mycket större kan ett annat användargränssnitt fungera bättre. Men metoden för att hantera en många-till-många-relation som visas här skulle inte ändras. För att skapa eller ta bort relationer manipulerar du en kopplingsentitet.
Skapa en klass för tilldelade kursdata
Skapa Models/SchoolViewModels/AssignedCourseData.cs med följande kod:
namespace ContosoUniversity.Models.SchoolViewModels
{
    public class AssignedCourseData
    {
        public int CourseID { get; set; }
        public string Title { get; set; }
        public bool Assigned { get; set; }
    }
}
Klassen AssignedCourseData innehåller data för att skapa kryssrutorna för kurser som tilldelats en lärare.
Skapa en instruktörssida modell basklass
Skapa basklassen Pages/Instructors/InstructorCoursesPageModel.cs :
using ContosoUniversity.Data;
using ContosoUniversity.Models;
using ContosoUniversity.Models.SchoolViewModels;
using Microsoft.AspNetCore.Mvc.RazorPages;
using System.Collections.Generic;
using System.Linq;
namespace ContosoUniversity.Pages.Instructors
{
    public class InstructorCoursesPageModel : PageModel
    {
        public List<AssignedCourseData> AssignedCourseDataList;
        public void PopulateAssignedCourseData(SchoolContext context,
                                               Instructor instructor)
        {
            var allCourses = context.Courses;
            var instructorCourses = new HashSet<int>(
                instructor.Courses.Select(c => c.CourseID));
            AssignedCourseDataList = new List<AssignedCourseData>();
            foreach (var course in allCourses)
            {
                AssignedCourseDataList.Add(new AssignedCourseData
                {
                    CourseID = course.CourseID,
                    Title = course.Title,
                    Assigned = instructorCourses.Contains(course.CourseID)
                });
            }
        }
    }
}
              InstructorCoursesPageModel är basklassen för sidmodellerna Redigera och Skapa. 
              PopulateAssignedCourseData läser alla Course entiteter för att fylla i AssignedCourseDataList. För varje kurs anger CourseID koden, rubriken och om läraren är tilldelad till kursen eller inte. En HashSet används för effektiva sökningar.
Hantera kontorsplats
En annan relation som redigeringssidan måste hantera är den en-till-noll-eller-en-relation som entiteten Instructor har med entiteten OfficeAssignment . Redigeringskoden för lärare måste hantera följande scenarier:
- Om användaren rensar tilldelningen för kontoret, ta bort 
OfficeAssignment-entiteten. - Om användaren anger en kontorstilldelning och den var tom, ska en ny 
OfficeAssignmententitet skapas. - Om användaren ändrar kontortilldelningen, uppdatera entiteten 
OfficeAssignment. 
Uppdatera instruktörens redigeringssida
Uppdatera Pages/Instructors/Edit.cshtml.cs med följande kod:
using ContosoUniversity.Models;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace ContosoUniversity.Pages.Instructors
{
    public class EditModel : InstructorCoursesPageModel
    {
        private readonly ContosoUniversity.Data.SchoolContext _context;
        public EditModel(ContosoUniversity.Data.SchoolContext context)
        {
            _context = context;
        }
        [BindProperty]
        public Instructor Instructor { get; set; }
        public async Task<IActionResult> OnGetAsync(int? id)
        {
            if (id == null)
            {
                return NotFound();
            }
            Instructor = await _context.Instructors
                .Include(i => i.OfficeAssignment)
                .Include(i => i.Courses)
                .AsNoTracking()
                .FirstOrDefaultAsync(m => m.ID == id);
            if (Instructor == null)
            {
                return NotFound();
            }
            PopulateAssignedCourseData(_context, Instructor);
            return Page();
        }
        public async Task<IActionResult> OnPostAsync(int? id, string[] selectedCourses)
        {
            if (id == null)
            {
                return NotFound();
            }
            var instructorToUpdate = await _context.Instructors
                .Include(i => i.OfficeAssignment)
                .Include(i => i.Courses)
                .FirstOrDefaultAsync(s => s.ID == id);
            if (instructorToUpdate == null)
            {
                return NotFound();
            }
            if (await TryUpdateModelAsync<Instructor>(
                instructorToUpdate,
                "Instructor",
                i => i.FirstMidName, i => i.LastName,
                i => i.HireDate, i => i.OfficeAssignment))
            {
                if (String.IsNullOrWhiteSpace(
                    instructorToUpdate.OfficeAssignment?.Location))
                {
                    instructorToUpdate.OfficeAssignment = null;
                }
                UpdateInstructorCourses(selectedCourses, instructorToUpdate);
                await _context.SaveChangesAsync();
                return RedirectToPage("./Index");
            }
            UpdateInstructorCourses(selectedCourses, instructorToUpdate);
            PopulateAssignedCourseData(_context, instructorToUpdate);
            return Page();
        }
        public 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 _context.Courses)
            {
                if (selectedCoursesHS.Contains(course.CourseID.ToString()))
                {
                    if (!instructorCourses.Contains(course.CourseID))
                    {
                        instructorToUpdate.Courses.Add(course);
                    }
                }
                else
                {
                    if (instructorCourses.Contains(course.CourseID))
                    {
                        var courseToRemove = instructorToUpdate.Courses.Single(
                                                        c => c.CourseID == course.CourseID);
                        instructorToUpdate.Courses.Remove(courseToRemove);
                    }
                }
            }
        }
    }
}
Föregående kod:
- Hämtar den aktuella 
Instructorentiteten från databasen med ivrig inläsning för navigeringsegenskapernaOfficeAssignmentochCourses. - Uppdaterar den hämtade entiteten 
Instructormed värden från modellbindaren. TryUpdateModelAsync förhindrar överpublicering. - Om kontorsplatsen är tom anger du 
Instructor.OfficeAssignmenttill null. NärInstructor.OfficeAssignmentär null tas den relaterade raden iOfficeAssignmenttabellen bort. - Anropar 
PopulateAssignedCourseDatainOnGetAsyncför att ange information om kryssrutorna med hjälp av visningsmodellklassenAssignedCourseData. - Anropar 
UpdateInstructorCoursesiOnPostAsyncför att tillämpa information från kryssrutorna på entiteten Instructor som redigeras. - Anrop 
PopulateAssignedCourseDataochUpdateInstructorCoursesinOnPostAsyncom TryUpdateModelAsync misslyckas. Dessa metodanrop återställer de tilldelade kursdata som anges på sidan när sidan visas igen med ett felmeddelande. 
Eftersom sidan Razor inte har en samling kursentiteter kan modellbindningen inte automatiskt uppdatera navigeringsegenskapen Courses . I stället för att använda modellbindningen för att uppdatera navigeringsegenskapen Courses görs det i den nya UpdateInstructorCourses metoden. Därför måste du undanta egenskapen Courses från modellbindningen. Detta kräver ingen ändring av koden som anropar TryUpdateModelAsync eftersom du använder den överlagrade metoden med deklarerade egenskaper och Courses inte finns med i inkluderingslistan.
Om inga kryssrutor har markerats initierar UpdateInstructorCourses koden i instructorToUpdate.Courses med en tom samling och returnerar:
if (selectedCourses == null)
{
    instructorToUpdate.Courses = new List<Course>();
    return;
}
Koden loopar sedan igenom alla kurser i databasen och kontrollerar varje kurs mot de som för närvarande är tilldelade till instruktören jämfört med de som valdes på sidan. För att underlätta effektiva sökningar lagras de två senare samlingarna i HashSet objekt.
Om kryssrutan för en kurs är markerad men kursen inte finns i navigeringsegenskapen Instructor.Courses läggs kursen till i samlingen i navigeringsegenskapen.
if (selectedCoursesHS.Contains(course.CourseID.ToString()))
{
    if (!instructorCourses.Contains(course.CourseID))
    {
        instructorToUpdate.Courses.Add(course);
    }
}
Om kryssrutan för en kurs inte är markerad, men kursen finns i navigeringsegenskapen Instructor.Courses , tas kursen bort från navigeringsegenskapen.
else
{
    if (instructorCourses.Contains(course.CourseID))
    {
        var courseToRemove = instructorToUpdate.Courses.Single(
                                        c => c.CourseID == course.CourseID);
        instructorToUpdate.Courses.Remove(courseToRemove);
    }
}
Uppdatera sidan Instruktörsredigering Razor
Uppdatera Pages/Instructors/Edit.cshtml med följande kod:
@page
@model ContosoUniversity.Pages.Instructors.EditModel
@{
    ViewData["Title"] = "Edit";
}
<h2>Edit</h2>
<h4>Instructor</h4>
<hr />
<div class="row">
    <div class="col-md-4">
        <form method="post">
            <div asp-validation-summary="ModelOnly" class="text-danger"></div>
            <input type="hidden" asp-for="Instructor.ID" />
            <div class="form-group">
                <label asp-for="Instructor.LastName" class="control-label"></label>
                <input asp-for="Instructor.LastName" class="form-control" />
                <span asp-validation-for="Instructor.LastName" class="text-danger"></span>
            </div>
            <div class="form-group">
                <label asp-for="Instructor.FirstMidName" class="control-label"></label>
                <input asp-for="Instructor.FirstMidName" class="form-control" />
                <span asp-validation-for="Instructor.FirstMidName" class="text-danger"></span>
            </div>
            <div class="form-group">
                <label asp-for="Instructor.HireDate" class="control-label"></label>
                <input asp-for="Instructor.HireDate" class="form-control" />
                <span asp-validation-for="Instructor.HireDate" class="text-danger"></span>
            </div>
            <div class="form-group">
                <label asp-for="Instructor.OfficeAssignment.Location" class="control-label"></label>
                <input asp-for="Instructor.OfficeAssignment.Location" class="form-control" />
                <span asp-validation-for="Instructor.OfficeAssignment.Location" class="text-danger" />
            </div>
            <div class="form-group">
                <div class="table">
                    <table>
                        <tr>
                            @{
                                int cnt = 0;
                                foreach (var course in Model.AssignedCourseDataList)
                                {
                                    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>
            <div class="form-group">
                <input type="submit" value="Save" class="btn btn-primary" />
            </div>
        </form>
    </div>
</div>
<div>
    <a asp-page="./Index">Back to List</a>
</div>
@section Scripts {
    @{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
}
Föregående kod skapar en HTML-tabell som har tre kolumner. Varje kolumn har en kryssruta och en bildtext som innehåller kursnummer och rubrik. Kryssrutorna har samma namn ("selectedCourses"). Med samma namn informerar man modellbindaren om att behandla dem som en grupp. Värdeattributet för varje kryssruta är inställt på CourseID. När sidan publiceras skickar modellbindaren en matris som endast består av CourseID värden för de markerade kryssrutorna.
När kryssrutorna ursprungligen återges väljs de kurser som har tilldelats instruktören.
Obs! Den metod som används här för att redigera lärarkursdata fungerar bra när det finns ett begränsat antal kurser. För samlingar som är mycket större skulle ett annat användargränssnitt och en annan uppdateringsmetod vara mer användbara och effektiva.
Kör appen och testa den uppdaterade lärarredigeringssidan. Ändra vissa kurstilldelningar. Ändringarna återspeglas på sidan Index.
Uppdatera sidan Skapa lärare
Uppdatera instruktörens modell för att skapa sidor och med kod som liknar sidan Redigera:
using ContosoUniversity.Data;
using ContosoUniversity.Models;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
namespace ContosoUniversity.Pages.Instructors
{
    public class CreateModel : InstructorCoursesPageModel
    {
        private readonly ContosoUniversity.Data.SchoolContext _context;
        private readonly ILogger<InstructorCoursesPageModel> _logger;
        public CreateModel(SchoolContext context,
                          ILogger<InstructorCoursesPageModel> logger)
        {
            _context = context;
            _logger = logger;
        }
        public IActionResult OnGet()
        {
            var instructor = new Instructor();
            instructor.Courses = new List<Course>();
            // Provides an empty collection for the foreach loop
            // foreach (var course in Model.AssignedCourseDataList)
            // in the Create Razor page.
            PopulateAssignedCourseData(_context, instructor);
            return Page();
        }
        [BindProperty]
        public Instructor Instructor { get; set; }
        public async Task<IActionResult> OnPostAsync(string[] selectedCourses)
        {
            var newInstructor = new Instructor();
            if (selectedCourses.Length > 0)
            {
                newInstructor.Courses = new List<Course>();
                // Load collection with one DB call.
                _context.Courses.Load();
            }
            // Add selected Courses courses to the new instructor.
            foreach (var course in selectedCourses)
            {
                var foundCourse = await _context.Courses.FindAsync(int.Parse(course));
                if (foundCourse != null)
                {
                    newInstructor.Courses.Add(foundCourse);
                }
                else
                {
                    _logger.LogWarning("Course {course} not found", course);
                }
            }
            try
            {
                if (await TryUpdateModelAsync<Instructor>(
                                newInstructor,
                                "Instructor",
                                i => i.FirstMidName, i => i.LastName,
                                i => i.HireDate, i => i.OfficeAssignment))
                {
                    _context.Instructors.Add(newInstructor);
                    await _context.SaveChangesAsync();
                    return RedirectToPage("./Index");
                }
                return RedirectToPage("./Index");
            }
            catch (Exception ex)
            {
                _logger.LogError(ex.Message);
            }
            PopulateAssignedCourseData(_context, newInstructor);
            return Page();
        }
    }
}
Föregående kod:
Lägger till loggning för varnings- och felmeddelanden.
Anropar Load, som hämtar alla kurser i ett databasanrop. För små samlingar är detta en optimering när du använder FindAsync.
FindAsyncreturnerar den spårade entiteten utan en begäran till databasen.public async Task<IActionResult> OnPostAsync(string[] selectedCourses) { var newInstructor = new Instructor(); if (selectedCourses.Length > 0) { newInstructor.Courses = new List<Course>(); // Load collection with one DB call. _context.Courses.Load(); } // Add selected Courses courses to the new instructor. foreach (var course in selectedCourses) { var foundCourse = await _context.Courses.FindAsync(int.Parse(course)); if (foundCourse != null) { newInstructor.Courses.Add(foundCourse); } else { _logger.LogWarning("Course {course} not found", course); } } try { if (await TryUpdateModelAsync<Instructor>( newInstructor, "Instructor", i => i.FirstMidName, i => i.LastName, i => i.HireDate, i => i.OfficeAssignment)) { _context.Instructors.Add(newInstructor); await _context.SaveChangesAsync(); return RedirectToPage("./Index"); } return RedirectToPage("./Index"); } catch (Exception ex) { _logger.LogError(ex.Message); } PopulateAssignedCourseData(_context, newInstructor); return Page(); }_context.Instructors.Add(newInstructor)skapar en nyInstructormed många-till-många-relationer utan att uttryckligen mappa kopplingstabellen. Många-till-många lades till i EF 5.0.
Testa sidan Skapa för instruktör.
Uppdatera sidan Skapa Razor lärare med kod som liknar sidan Redigera:
@page
@model ContosoUniversity.Pages.Instructors.CreateModel
@{
    ViewData["Title"] = "Create";
}
<h2>Create</h2>
<h4>Instructor</h4>
<hr />
<div class="row">
    <div class="col-md-4">
        <form method="post">
            <div asp-validation-summary="ModelOnly" class="text-danger"></div>
            <div class="form-group">
                <label asp-for="Instructor.LastName" class="control-label"></label>
                <input asp-for="Instructor.LastName" class="form-control" />
                <span asp-validation-for="Instructor.LastName" class="text-danger"></span>
            </div>
            <div class="form-group">
                <label asp-for="Instructor.FirstMidName" class="control-label"></label>
                <input asp-for="Instructor.FirstMidName" class="form-control" />
                <span asp-validation-for="Instructor.FirstMidName" class="text-danger"></span>
            </div>
            <div class="form-group">
                <label asp-for="Instructor.HireDate" class="control-label"></label>
                <input asp-for="Instructor.HireDate" class="form-control" />
                <span asp-validation-for="Instructor.HireDate" class="text-danger"></span>
            </div>
            <div class="form-group">
                <label asp-for="Instructor.OfficeAssignment.Location" class="control-label"></label>
                <input asp-for="Instructor.OfficeAssignment.Location" class="form-control" />
                <span asp-validation-for="Instructor.OfficeAssignment.Location" class="text-danger" />
            </div>
            <div class="form-group">
                <div class="table">
                    <table>
                        <tr>
                            @{
                                int cnt = 0;
                                foreach (var course in Model.AssignedCourseDataList)
                                {
                                    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>
            <div class="form-group">
                <input type="submit" value="Create" class="btn btn-primary" />
            </div>
        </form>
    </div>
</div>
<div>
    <a asp-page="Index">Back to List</a>
</div>
@section Scripts {
    @{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
}
Uppdatera sidan för att ta bort lärare
Uppdatera Pages/Instructors/Delete.cshtml.cs med följande kod:
using ContosoUniversity.Models;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.EntityFrameworkCore;
using System.Linq;
using System.Threading.Tasks;
namespace ContosoUniversity.Pages.Instructors
{
    public class DeleteModel : PageModel
    {
        private readonly ContosoUniversity.Data.SchoolContext _context;
        public DeleteModel(ContosoUniversity.Data.SchoolContext context)
        {
            _context = context;
        }
        [BindProperty]
        public Instructor Instructor { get; set; }
        public async Task<IActionResult> OnGetAsync(int? id)
        {
            if (id == null)
            {
                return NotFound();
            }
            Instructor = await _context.Instructors.FirstOrDefaultAsync(m => m.ID == id);
            if (Instructor == null)
            {
                return NotFound();
            }
            return Page();
        }
        public async Task<IActionResult> OnPostAsync(int? id)
        {
            if (id == null)
            {
                return NotFound();
            }
            Instructor instructor = await _context.Instructors
                .Include(i => i.Courses)
                .SingleAsync(i => i.ID == id);
            if (instructor == null)
            {
                return RedirectToPage("./Index");
            }
            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 RedirectToPage("./Index");
        }
    }
}
Föregående kod gör följande ändringar:
Använder ivrig inläsning för navigeringsegenskapen
Courses.Coursesmåste inkluderas eller så tas de inte bort när instruktören tas bort. Om du vill undvika att behöva läsa dem konfigurerar du kaskadborttagning i databasen.Om instruktören som ska tas bort tilldelas som administratör för några avdelningar tar du bort lärartilldelningen från dessa avdelningar.
Kör appen och testa sidan Ta bort.
Nästa steg
Den här handledningen visar hur du uppdaterar relaterad data. Följande bilder visar några av de slutförda sidorna.
              
              
              
              
            
Uppdatera kurssidorna för att skapa och redigera kurser
Den scaffoldade koden för sidorna för Kurs Skapa och Redigera har en listruta för avdelningar som visar avdelnings-ID (ett heltal). Listrutan bör visa avdelningsnamnet, så båda dessa sidor behöver en lista med avdelningsnamn. Om du vill ange den listan använder du en basklass för sidorna Skapa och redigera.
Skapa en basklass för Kursskapa och redigera
Skapa en Pages/Courses/DepartmentNamePageModel.cs fil med följande kod:
using ContosoUniversity.Data;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.AspNetCore.Mvc.Rendering;
using Microsoft.EntityFrameworkCore;
using System.Linq;
namespace ContosoUniversity.Pages.Courses
{
    public class DepartmentNamePageModel : PageModel
    {
        public SelectList DepartmentNameSL { get; set; }
        public void PopulateDepartmentsDropDownList(SchoolContext _context,
            object selectedDepartment = null)
        {
            var departmentsQuery = from d in _context.Departments
                                   orderby d.Name // Sort by name.
                                   select d;
            DepartmentNameSL = new SelectList(departmentsQuery.AsNoTracking(),
                        "DepartmentID", "Name", selectedDepartment);
        }
    }
}
Föregående kod skapar en SelectList för att innehålla listan över avdelningsnamn. Parametern selectedDepartment gör att den anropande koden kan ange det objekt som ska väljas när listrutan återges. Men när du använder hjälpverktyget Välj tagg med asp-forbestäms det valda objektet av modellegenskapsvärdet (till exempel Course.DepartmentID), inte av parametern selectedDepartment .
Klasserna Skapa och redigera sidmodell härleds från DepartmentNamePageModel.
Uppdatera sidmodellen för kursskapande
En kurs tilldelas till en avdelning. Basklassen för sidorna Skapa och redigera innehåller en SelectList för att välja avdelning. Listrutan som använder SelectList anger Course.DepartmentID egenskapen främmande nyckel (FK). 
              EF Core använder FK:n Course.DepartmentID för att infoga navigeringsegenskap Department.
              
              
            
Uppdatera Pages/Courses/Create.cshtml.cs med följande kod:
using ContosoUniversity.Models;
using Microsoft.AspNetCore.Mvc;
using System.Threading.Tasks;
namespace ContosoUniversity.Pages.Courses
{
    public class CreateModel : DepartmentNamePageModel
    {
        private readonly ContosoUniversity.Data.SchoolContext _context;
        public CreateModel(ContosoUniversity.Data.SchoolContext context)
        {
            _context = context;
        }
        public IActionResult OnGet()
        {
            PopulateDepartmentsDropDownList(_context);
            return Page();
        }
        [BindProperty]
        public Course Course { get; set; }
        public async Task<IActionResult> OnPostAsync()
        {
            var emptyCourse = new Course();
            if (await TryUpdateModelAsync<Course>(
                 emptyCourse,
                 "course",   // Prefix for form value.
                 s => s.CourseID, s => s.DepartmentID, s => s.Title, s => s.Credits))
            {
                _context.Courses.Add(emptyCourse);
                await _context.SaveChangesAsync();
                return RedirectToPage("./Index");
            }
            // Repopulate departments dropdown. emptyCourse.DepartmentID determines the selected item.
            PopulateDepartmentsDropDownList(_context, emptyCourse.DepartmentID);
            return Page();
        }
      }
}
Om du vill se kodkommentar översatta till andra språk än engelska kan du meddela oss i det här GitHub-diskussionsproblemet.
Föregående kod:
- Härleds från 
DepartmentNamePageModel. - Används 
TryUpdateModelAsyncför att förhindra överpublicering. - Tar bort 
ViewData["DepartmentID"].DepartmentNameSLfrån basklassen är en starkt typad modell och används av sidan Razor. Starkt skrivna modeller föredras framför svagt skrivna. Mer information finns i Svagt inskrivna data (ViewData och ViewBag). 
Uppdatera Kursskapandets sida Razor
Uppdatera Pages/Courses/Create.cshtml med följande kod:
@page
@model ContosoUniversity.Pages.Courses.CreateModel
@{
    ViewData["Title"] = "Create Course";
}
<h2>Create</h2>
<h4>Course</h4>
<hr />
<div class="row">
    <div class="col-md-4">
        <form method="post">
            <div asp-validation-summary="ModelOnly" class="text-danger"></div>
            <div class="form-group">
                <label asp-for="Course.CourseID" class="control-label"></label>
                <input asp-for="Course.CourseID" class="form-control" />
                <span asp-validation-for="Course.CourseID" class="text-danger"></span>
            </div>
            <div class="form-group">
                <label asp-for="Course.Title" class="control-label"></label>
                <input asp-for="Course.Title" class="form-control" />
                <span asp-validation-for="Course.Title" class="text-danger"></span>
            </div>
            <div class="form-group">
                <label asp-for="Course.Credits" class="control-label"></label>
                <input asp-for="Course.Credits" class="form-control" />
                <span asp-validation-for="Course.Credits" class="text-danger"></span>
            </div>
            <div class="form-group">
                <label asp-for="Course.Department" class="control-label"></label>
                <select asp-for="Course.DepartmentID" class="form-control"
                        asp-items="@Model.DepartmentNameSL">
                    <option value="">-- Select Department --</option>
                </select>
                <span asp-validation-for="Course.DepartmentID" class="text-danger" />
            </div>
            <div class="form-group">
                <input type="submit" value="Create" class="btn btn-primary" />
            </div>
        </form>
    </div>
</div>
<div>
    <a asp-page="Index">Back to List</a>
</div>
@section Scripts {
    @{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
}
Föregående kod gör följande ändringar:
- Ändrar bildtexten från DepartmentID till Department.
 - 
              
"ViewBag.DepartmentID"Ersätter medDepartmentNameSL(från basklassen). - Lägger till alternativet "Välj avdelning". Den här ändringen återger "Välj avdelning" i listrutan när ingen avdelning har valts ännu, i stället för den första avdelningen.
 - Lägger till ett valideringsmeddelande när avdelningen inte har valts.
 
Sidan Razor använder hjälpen Välj tagg:
<div class="form-group">
    <label asp-for="Course.Department" class="control-label"></label>
    <select asp-for="Course.DepartmentID" class="form-control"
            asp-items="@Model.DepartmentNameSL">
        <option value="">-- Select Department --</option>
    </select>
    <span asp-validation-for="Course.DepartmentID" class="text-danger" />
</div>
Testa Skapa-sidan. På sidan Skapa visas avdelningsnamnet i stället för avdelnings-ID:t.
Uppdatera kursredigeringssidemodellen
Uppdatera Pages/Courses/Edit.cshtml.cs med följande kod:
using ContosoUniversity.Models;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using System.Threading.Tasks;
namespace ContosoUniversity.Pages.Courses
{
    public class EditModel : DepartmentNamePageModel
    {
        private readonly ContosoUniversity.Data.SchoolContext _context;
        public EditModel(ContosoUniversity.Data.SchoolContext context)
        {
            _context = context;
        }
        [BindProperty]
        public Course Course { get; set; }
        public async Task<IActionResult> OnGetAsync(int? id)
        {
            if (id == null)
            {
                return NotFound();
            }
            Course = await _context.Courses
                .Include(c => c.Department).FirstOrDefaultAsync(m => m.CourseID == id);
            if (Course == null)
            {
                return NotFound();
            }
            // Populate departments dropdown. Course.DepartmentID determines the selected item.
            PopulateDepartmentsDropDownList(_context, Course.DepartmentID);
            return Page();
        }
        public async Task<IActionResult> OnPostAsync(int? id)
        {
            if (id == null)
            {
                return NotFound();
            }
            var courseToUpdate = await _context.Courses.FindAsync(id);
            if (courseToUpdate == null)
            {
                return NotFound();
            }
            if (await TryUpdateModelAsync<Course>(
                 courseToUpdate,
                 "course",   // Prefix for form value.
                   c => c.Credits, c => c.DepartmentID, c => c.Title))
            {
                await _context.SaveChangesAsync();
                return RedirectToPage("./Index");
            }
            // Repopulate departments dropdown. courseToUpdate.DepartmentID determines the selected item.
            PopulateDepartmentsDropDownList(_context, courseToUpdate.DepartmentID);
            return Page();
        }       
    }
}
Ändringarna liknar dem som gjordes i Skapa sidmodellen. I föregående kod PopulateDepartmentsDropDownList anger du avdelnings-ID. När du använder hjälpverktyget Välj tagg med asp-for="Course.DepartmentID"bestäms det markerade objektet i listrutan av Course.DepartmentIDvärdet för , inte av parametern selectedDepartment som skickas till konstruktorn SelectList.
Uppdatera sidan Kursredigering Razor
Uppdatera Pages/Courses/Edit.cshtml med följande kod:
@page
@model ContosoUniversity.Pages.Courses.EditModel
@{
    ViewData["Title"] = "Edit";
}
<h2>Edit</h2>
<h4>Course</h4>
<hr />
<div class="row">
    <div class="col-md-4">
        <form method="post">
            <div asp-validation-summary="ModelOnly" class="text-danger"></div>
            <input type="hidden" asp-for="Course.CourseID" />
            <div class="form-group">
                <label asp-for="Course.CourseID" class="control-label"></label>
                <div>@Html.DisplayFor(model => model.Course.CourseID)</div>
            </div>
            <div class="form-group">
                <label asp-for="Course.Title" class="control-label"></label>
                <input asp-for="Course.Title" class="form-control" />
                <span asp-validation-for="Course.Title" class="text-danger"></span>
            </div>
            <div class="form-group">
                <label asp-for="Course.Credits" class="control-label"></label>
                <input asp-for="Course.Credits" class="form-control" />
                <span asp-validation-for="Course.Credits" class="text-danger"></span>
            </div>
            <div class="form-group">
                <label asp-for="Course.Department" class="control-label"></label>
                <select asp-for="Course.DepartmentID" class="form-control" 
                        asp-items="@Model.DepartmentNameSL"></select>
                <span asp-validation-for="Course.DepartmentID" class="text-danger"></span>
            </div>
            <div class="form-group">
                <input type="submit" value="Save" class="btn btn-primary" />
            </div>
        </form>
    </div>
</div>
<div>
    <a asp-page="./Index">Back to List</a>
</div>
@section Scripts {
    @{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
}
Föregående kod gör följande ändringar:
- Visar kurs-ID. Vanligtvis visas inte primärnyckeln (PK) för en entitet. PK:er är vanligtvis meningslösa för användarna. I det här fallet är PK:t kursnumret.
 - Ändrar beskrivningen för listrutan Avdelning från DepartmentID till Avdelning.
 - 
              
"ViewBag.DepartmentID"Ersätter medDepartmentNameSL(från basklassen). 
Sidan innehåller ett dolt fält (<input type="hidden">) för kursnumret. Att lägga till en <label> tag helper med asp-for="Course.CourseID" eliminerar inte behovet av det dolda fältet. 
              <input type="hidden"> krävs för att kursnumret ska inkluderas i de publicerade data när användaren klickar på Spara.
Uppdatera kursinformationen och ta bort sidor
AsNoTracking kan förbättra prestanda när spårning inte krävs.
Uppdatera kurssidans modeller
Uppdatera Pages/Courses/Delete.cshtml.cs med följande kod för att lägga till AsNoTracking:
using ContosoUniversity.Models;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.EntityFrameworkCore;
using System.Threading.Tasks;
namespace ContosoUniversity.Pages.Courses
{
    public class DeleteModel : PageModel
    {
        private readonly ContosoUniversity.Data.SchoolContext _context;
        public DeleteModel(ContosoUniversity.Data.SchoolContext context)
        {
            _context = context;
        }
        [BindProperty]
        public Course Course { get; set; }
        public async Task<IActionResult> OnGetAsync(int? id)
        {
            if (id == null)
            {
                return NotFound();
            }
            Course = await _context.Courses
                .AsNoTracking()
                .Include(c => c.Department)
                .FirstOrDefaultAsync(m => m.CourseID == id);
            if (Course == null)
            {
                return NotFound();
            }
            return Page();
        }
        public async Task<IActionResult> OnPostAsync(int? id)
        {
            if (id == null)
            {
                return NotFound();
            }
            Course = await _context.Courses.FindAsync(id);
            if (Course != null)
            {
                _context.Courses.Remove(Course);
                await _context.SaveChangesAsync();
            }
            return RedirectToPage("./Index");
        }
    }
}
Gör samma ändring i Pages/Courses/Details.cshtml.cs filen:
using ContosoUniversity.Models;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.EntityFrameworkCore;
using System.Threading.Tasks;
namespace ContosoUniversity.Pages.Courses
{
    public class DetailsModel : PageModel
    {
        private readonly ContosoUniversity.Data.SchoolContext _context;
        public DetailsModel(ContosoUniversity.Data.SchoolContext context)
        {
            _context = context;
        }
        public Course Course { get; set; }
        public async Task<IActionResult> OnGetAsync(int? id)
        {
            if (id == null)
            {
                return NotFound();
            }
            Course = await _context.Courses
                 .AsNoTracking()
                 .Include(c => c.Department)
                 .FirstOrDefaultAsync(m => m.CourseID == id);
            if (Course == null)
            {
                return NotFound();
            }
            return Page();
        }
    }
}
Uppdatera kurs Razor-sidorna
Uppdatera Pages/Courses/Delete.cshtml med följande kod:
@page
@model ContosoUniversity.Pages.Courses.DeleteModel
@{
    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.Course.CourseID)
        </dt>
        <dd class="col-sm-10">
            @Html.DisplayFor(model => model.Course.CourseID)
        </dd>
        <dt class="col-sm-2">
            @Html.DisplayNameFor(model => model.Course.Title)
        </dt>
        <dd class="col-sm-10">
            @Html.DisplayFor(model => model.Course.Title)
        </dd>
        <dt class="col-sm-2">
            @Html.DisplayNameFor(model => model.Course.Credits)
        </dt>
        <dd class="col-sm-10">
            @Html.DisplayFor(model => model.Course.Credits)
        </dd>
        <dt class="col-sm-2">
            @Html.DisplayNameFor(model => model.Course.Department)
        </dt>
        <dd class="col-sm-10">
            @Html.DisplayFor(model => model.Course.Department.Name)
        </dd>
    </dl>
    
    <form method="post">
        <input type="hidden" asp-for="Course.CourseID" />
        <input type="submit" value="Delete" class="btn btn-danger" /> |
        <a asp-page="./Index">Back to List</a>
    </form>
</div>
Gör samma ändringar på sidan Information.
@page
@model ContosoUniversity.Pages.Courses.DetailsModel
@{
    ViewData["Title"] = "Details";
}
<h2>Details</h2>
<div>
    <h4>Course</h4>
    <hr />
    <dl class="row">
        <dt class="col-sm-2">
            @Html.DisplayNameFor(model => model.Course.CourseID)
        </dt>
        <dd class="col-sm-10">
            @Html.DisplayFor(model => model.Course.CourseID)
        </dd>
        <dt class="col-sm-2">
            @Html.DisplayNameFor(model => model.Course.Title)
        </dt>
        <dd class="col-sm-10">
            @Html.DisplayFor(model => model.Course.Title)
        </dd>
        <dt class="col-sm-2">
            @Html.DisplayNameFor(model => model.Course.Credits)
        </dt>
        <dd class="col-sm-10">
            @Html.DisplayFor(model => model.Course.Credits)
        </dd>
        <dt class="col-sm-2">
            @Html.DisplayNameFor(model => model.Course.Department)
        </dt>
        <dd class="col-sm-10">
            @Html.DisplayFor(model => model.Course.Department.Name)
        </dd>
    </dl>
</div>
<div>
    <a asp-page="./Edit" asp-route-id="@Model.Course.CourseID">Edit</a> |
    <a asp-page="./Index">Back to List</a>
</div>
Testa kursens sidor
Testa skapa, redigera, visa information och ta bort-sidorna.
Uppdatera instruktören Skapa och redigera sidor
Instruktörer kan undervisa valfritt antal kurser. Följande bild visar instruktörens redigeringssida med en uppsättning av kurser i kryssrutor.
              
              
            
Kryssrutorna gör det möjligt att ändra kurser som en lärare har tilldelats till. En kryssruta visas för varje kurs i databasen. Kurser som instruktören är tilldelad till väljs. Användaren kan markera eller avmarkera kryssrutor för att ändra kurstilldelningar. Om antalet kurser var mycket större kan ett annat användargränssnitt fungera bättre. Men metoden för att hantera en många-till-många-relation som visas här skulle inte ändras. För att skapa eller ta bort relationer manipulerar du en kopplingsentitet.
Skapa en klass för tilldelade kursdata
Skapa Models/SchoolViewModels/AssignedCourseData.cs med följande kod:
namespace ContosoUniversity.Models.SchoolViewModels
{
    public class AssignedCourseData
    {
        public int CourseID { get; set; }
        public string Title { get; set; }
        public bool Assigned { get; set; }
    }
}
Klassen AssignedCourseData innehåller data för att skapa kryssrutorna för kurser som tilldelats en lärare.
Skapa en instruktörssida modell basklass
Skapa basklassen Pages/Instructors/InstructorCoursesPageModel.cs :
using ContosoUniversity.Data;
using ContosoUniversity.Models;
using ContosoUniversity.Models.SchoolViewModels;
using Microsoft.AspNetCore.Mvc.RazorPages;
using System.Collections.Generic;
using System.Linq;
namespace ContosoUniversity.Pages.Instructors
{
    public class InstructorCoursesPageModel : PageModel
    {
        public List<AssignedCourseData> AssignedCourseDataList;
        public void PopulateAssignedCourseData(SchoolContext context, 
                                               Instructor instructor)
        {
            var allCourses = context.Courses;
            var instructorCourses = new HashSet<int>(
                instructor.CourseAssignments.Select(c => c.CourseID));
            AssignedCourseDataList = new List<AssignedCourseData>();
            foreach (var course in allCourses)
            {
                AssignedCourseDataList.Add(new AssignedCourseData
                {
                    CourseID = course.CourseID,
                    Title = course.Title,
                    Assigned = instructorCourses.Contains(course.CourseID)
                });
            }
        }
        public void UpdateInstructorCourses(SchoolContext context, 
            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
                                .SingleOrDefault(i => i.CourseID == course.CourseID);
                        context.Remove(courseToRemove);
                    }
                }
            }
        }
    }
}
              InstructorCoursesPageModel är den basklass som du ska använda för sidmodellerna Redigera och Skapa. 
              PopulateAssignedCourseData läser alla Course entiteter för att fylla i AssignedCourseDataList. För varje kurs anger CourseID koden, rubriken och om läraren är tilldelad till kursen eller inte. En HashSet används för effektiva sökningar.
Eftersom sidan Razor inte har en samling kursentiteter kan modellbindningen inte automatiskt uppdatera navigeringsegenskapen CourseAssignments . I stället för att använda modellbindningen för att uppdatera navigeringsegenskapen CourseAssignments gör du det i den nya UpdateInstructorCourses metoden. Därför måste du undanta egenskapen CourseAssignments från modellbindningen. Detta kräver ingen ändring av koden som anropar TryUpdateModel eftersom du använder den överlagrade metoden med deklarerade egenskaper och CourseAssignments inte finns med i inkluderingslistan.
Om inga kryssrutor har markerats initierar koden i UpdateInstructorCourses navigeringsegenskapen CourseAssignments med en tom samling och returnerar:
if (selectedCourses == null)
{
    instructorToUpdate.CourseAssignments = new List<CourseAssignment>();
    return;
}
Koden loopar sedan igenom alla kurser i databasen och kontrollerar varje kurs mot de som för närvarande är tilldelade till instruktören jämfört med de som valdes på sidan. För att underlätta effektiva sökningar lagras de två senare samlingarna i HashSet objekt.
Om kryssrutan för en kurs har valts men kursen inte finns i navigeringsegenskapen Instructor.CourseAssignments läggs kursen till i samlingen i navigeringsegenskapen.
if (selectedCoursesHS.Contains(course.CourseID.ToString()))
{
    if (!instructorCourses.Contains(course.CourseID))
    {
        instructorToUpdate.CourseAssignments.Add(
            new CourseAssignment
            {
                InstructorID = instructorToUpdate.ID,
                CourseID = course.CourseID
            });
    }
}
Om kryssrutan för en kurs inte har valts, men kursen finns i navigeringsegenskapen Instructor.CourseAssignments , tas kursen bort från navigeringsegenskapen.
else
{
    if (instructorCourses.Contains(course.CourseID))
    {
        CourseAssignment courseToRemove
            = instructorToUpdate
                .CourseAssignments
                .SingleOrDefault(i => i.CourseID == course.CourseID);
        context.Remove(courseToRemove);
    }
}
Hantera kontorsplats
En annan relation som redigeringssidan måste hantera är den en-till-noll-eller-en-relation som entiteten Instructor har med entiteten OfficeAssignment . Redigeringskoden för lärare måste hantera följande scenarier:
- Om användaren rensar tilldelningen för kontoret, ta bort 
OfficeAssignment-entiteten. - Om användaren anger en kontorstilldelning och den var tom, ska en ny 
OfficeAssignmententitet skapas. - Om användaren ändrar kontortilldelningen, uppdatera entiteten 
OfficeAssignment. 
Uppdatera instruktörens redigeringssida
Uppdatera Pages/Instructors/Edit.cshtml.cs med följande kod:
using ContosoUniversity.Models;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using System;
using System.Threading.Tasks;
namespace ContosoUniversity.Pages.Instructors
{
    public class EditModel : InstructorCoursesPageModel
    {
        private readonly ContosoUniversity.Data.SchoolContext _context;
        public EditModel(ContosoUniversity.Data.SchoolContext context)
        {
            _context = context;
        }
        [BindProperty]
        public Instructor Instructor { get; set; }
        public async Task<IActionResult> OnGetAsync(int? id)
        {
            if (id == null)
            {
                return NotFound();
            }
            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(_context, Instructor);
            return Page();
        }
        public async Task<IActionResult> OnPostAsync(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 (instructorToUpdate == null)
            {
                return NotFound();
            }
            if (await TryUpdateModelAsync<Instructor>(
                instructorToUpdate,
                "Instructor",
                i => i.FirstMidName, i => i.LastName,
                i => i.HireDate, i => i.OfficeAssignment))
            {
                if (String.IsNullOrWhiteSpace(
                    instructorToUpdate.OfficeAssignment?.Location))
                {
                    instructorToUpdate.OfficeAssignment = null;
                }
                UpdateInstructorCourses(_context, selectedCourses, instructorToUpdate);
                await _context.SaveChangesAsync();
                return RedirectToPage("./Index");
            }
            UpdateInstructorCourses(_context, selectedCourses, instructorToUpdate);
            PopulateAssignedCourseData(_context, instructorToUpdate);
            return Page();
        }
    }
}
Föregående kod:
- Hämtar den aktuella 
Instructor-entiteten från databasen med explicit inläsning för navigeringsegenskapernaOfficeAssignment,CourseAssignmentochCourseAssignment.Course. - Uppdaterar den hämtade entiteten 
Instructormed värden från modellbindaren.TryUpdateModelförhindrar överpublicering. - Om kontorsplatsen är tom anger du 
Instructor.OfficeAssignmenttill null. NärInstructor.OfficeAssignmentär null tas den relaterade raden iOfficeAssignmenttabellen bort. - Anropar 
PopulateAssignedCourseDatainOnGetAsyncför att ange information om kryssrutorna med hjälp av visningsmodellklassenAssignedCourseData. - Anropar 
UpdateInstructorCoursesiOnPostAsyncför att tillämpa information från kryssrutorna på entiteten Instructor som redigeras. - Anrop 
PopulateAssignedCourseDataochUpdateInstructorCoursesinOnPostAsyncomTryUpdateModelmisslyckas. Dessa metodanrop återställer de tilldelade kursdata som anges på sidan när sidan visas igen med ett felmeddelande. 
Uppdatera sidan Instruktörsredigering Razor
Uppdatera Pages/Instructors/Edit.cshtml med följande kod:
@page
@model ContosoUniversity.Pages.Instructors.EditModel
@{
    ViewData["Title"] = "Edit";
}
<h2>Edit</h2>
<h4>Instructor</h4>
<hr />
<div class="row">
    <div class="col-md-4">
        <form method="post">
            <div asp-validation-summary="ModelOnly" class="text-danger"></div>
            <input type="hidden" asp-for="Instructor.ID" />
            <div class="form-group">
                <label asp-for="Instructor.LastName" class="control-label"></label>
                <input asp-for="Instructor.LastName" class="form-control" />
                <span asp-validation-for="Instructor.LastName" class="text-danger"></span>
            </div>
            <div class="form-group">
                <label asp-for="Instructor.FirstMidName" class="control-label"></label>
                <input asp-for="Instructor.FirstMidName" class="form-control" />
                <span asp-validation-for="Instructor.FirstMidName" class="text-danger"></span>
            </div>
            <div class="form-group">
                <label asp-for="Instructor.HireDate" class="control-label"></label>
                <input asp-for="Instructor.HireDate" class="form-control" />
                <span asp-validation-for="Instructor.HireDate" class="text-danger"></span>
            </div>
            <div class="form-group">
                <label asp-for="Instructor.OfficeAssignment.Location" class="control-label"></label>
                <input asp-for="Instructor.OfficeAssignment.Location" class="form-control" />
                <span asp-validation-for="Instructor.OfficeAssignment.Location" class="text-danger" />
            </div>
            <div class="form-group">
                <div class="table">
                    <table>
                        <tr>
                            @{
                                int cnt = 0;
                                foreach (var course in Model.AssignedCourseDataList)
                                {
                                    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>
            <div class="form-group">
                <input type="submit" value="Save" class="btn btn-primary" />
            </div>
        </form>
    </div>
</div>
<div>
    <a asp-page="./Index">Back to List</a>
</div>
@section Scripts {
    @{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
}
Föregående kod skapar en HTML-tabell som har tre kolumner. Varje kolumn har en kryssruta och en bildtext som innehåller kursnummer och rubrik. Kryssrutorna har samma namn ("selectedCourses"). Med samma namn informerar man modellbindaren om att behandla dem som en grupp. Värdeattributet för varje kryssruta är inställt på CourseID. När sidan publiceras skickar modellbindaren en matris som endast består av CourseID värden för de markerade kryssrutorna.
När kryssrutorna ursprungligen återges väljs de kurser som har tilldelats instruktören.
Obs! Den metod som används här för att redigera lärarkursdata fungerar bra när det finns ett begränsat antal kurser. För samlingar som är mycket större skulle ett annat användargränssnitt och en annan uppdateringsmetod vara mer användbara och effektiva.
Kör appen och testa den uppdaterade lärarredigeringssidan. Ändra vissa kurstilldelningar. Ändringarna återspeglas på sidan Index.
Uppdatera sidan Skapa lärare
Uppdatera instruktörens Skapa-sidmodell och Razor-sidan med kod liknande den på Redigera-sidan:
using ContosoUniversity.Models;
using Microsoft.AspNetCore.Mvc;
using System.Collections.Generic;
using System.Threading.Tasks;
namespace ContosoUniversity.Pages.Instructors
{
    public class CreateModel : InstructorCoursesPageModel
    {
        private readonly ContosoUniversity.Data.SchoolContext _context;
        public CreateModel(ContosoUniversity.Data.SchoolContext context)
        {
            _context = context;
        }
        public IActionResult OnGet()
        {
            var instructor = new Instructor();
            instructor.CourseAssignments = new List<CourseAssignment>();
            // Provides an empty collection for the foreach loop
            // foreach (var course in Model.AssignedCourseDataList)
            // in the Create Razor page.
            PopulateAssignedCourseData(_context, instructor);
            return Page();
        }
        [BindProperty]
        public Instructor Instructor { get; set; }
        public async Task<IActionResult> OnPostAsync(string[] selectedCourses)
        {
            var newInstructor = new Instructor();
            if (selectedCourses != null)
            {
                newInstructor.CourseAssignments = new List<CourseAssignment>();
                foreach (var course in selectedCourses)
                {
                    var courseToAdd = new CourseAssignment
                    {
                        CourseID = int.Parse(course)
                    };
                    newInstructor.CourseAssignments.Add(courseToAdd);
                }
            }
            if (await TryUpdateModelAsync<Instructor>(
                newInstructor,
                "Instructor",
                i => i.FirstMidName, i => i.LastName,
                i => i.HireDate, i => i.OfficeAssignment))
            {
                _context.Instructors.Add(newInstructor);                
                await _context.SaveChangesAsync();
                return RedirectToPage("./Index");
            }
            PopulateAssignedCourseData(_context, newInstructor);
            return Page();
        }
    }
}
@page
@model ContosoUniversity.Pages.Instructors.CreateModel
@{
    ViewData["Title"] = "Create";
}
<h2>Create</h2>
<h4>Instructor</h4>
<hr />
<div class="row">
    <div class="col-md-4">
        <form method="post">
            <div asp-validation-summary="ModelOnly" class="text-danger"></div>
            <div class="form-group">
                <label asp-for="Instructor.LastName" class="control-label"></label>
                <input asp-for="Instructor.LastName" class="form-control" />
                <span asp-validation-for="Instructor.LastName" class="text-danger"></span>
            </div>
            <div class="form-group">
                <label asp-for="Instructor.FirstMidName" class="control-label"></label>
                <input asp-for="Instructor.FirstMidName" class="form-control" />
                <span asp-validation-for="Instructor.FirstMidName" class="text-danger"></span>
            </div>
            <div class="form-group">
                <label asp-for="Instructor.HireDate" class="control-label"></label>
                <input asp-for="Instructor.HireDate" class="form-control" />
                <span asp-validation-for="Instructor.HireDate" class="text-danger"></span>
            </div>
            <div class="form-group">
                <label asp-for="Instructor.OfficeAssignment.Location" class="control-label"></label>
                <input asp-for="Instructor.OfficeAssignment.Location" class="form-control" />
                <span asp-validation-for="Instructor.OfficeAssignment.Location" class="text-danger" />
            </div>
            <div class="form-group">
                <div class="table">
                    <table>
                        <tr>
                            @{
                                int cnt = 0;
                                foreach (var course in Model.AssignedCourseDataList)
                                {
                                    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>
            <div class="form-group">
                <input type="submit" value="Create" class="btn btn-primary" />
            </div>
        </form>
    </div>
</div>
<div>
    <a asp-page="Index">Back to List</a>
</div>
@section Scripts {
    @{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
}
Testa sidan Skapa för instruktör.
Uppdatera sidan för att ta bort lärare
Uppdatera Pages/Instructors/Delete.cshtml.cs med följande kod:
using ContosoUniversity.Models;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.EntityFrameworkCore;
using System.Linq;
using System.Threading.Tasks;
namespace ContosoUniversity.Pages.Instructors
{
    public class DeleteModel : PageModel
    {
        private readonly ContosoUniversity.Data.SchoolContext _context;
        public DeleteModel(ContosoUniversity.Data.SchoolContext context)
        {
            _context = context;
        }
        [BindProperty]
        public Instructor Instructor { get; set; }
        public async Task<IActionResult> OnGetAsync(int? id)
        {
            if (id == null)
            {
                return NotFound();
            }
            Instructor = await _context.Instructors.FirstOrDefaultAsync(m => m.ID == id);
            if (Instructor == null)
            {
                return NotFound();
            }
            return Page();
        }
        public async Task<IActionResult> OnPostAsync(int? id)
        {
            if (id == null)
            {
                return NotFound();
            }
            Instructor instructor = await _context.Instructors
                .Include(i => i.CourseAssignments)
                .SingleAsync(i => i.ID == id);
            if (instructor == null)
            {
                return RedirectToPage("./Index");
            }
            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 RedirectToPage("./Index");
        }
    }
}
Föregående kod gör följande ändringar:
Använder ivrig inläsning för navigeringsegenskapen
CourseAssignments.CourseAssignmentsmåste inkluderas eller så tas de inte bort när instruktören tas bort. Om du vill undvika att behöva läsa dem konfigurerar du kaskadborttagning i databasen.Om instruktören som ska tas bort tilldelas som administratör för några avdelningar tar du bort lärartilldelningen från dessa avdelningar.
Kör appen och testa sidan Ta bort.
Nästa steg
Den här självstudien visar hur du uppdaterar relaterade data. Om du stöter på problem som du inte kan lösa ladda ned eller visa den färdiga appen.Ladda ned instruktioner.
Följande bilder visar några av de slutförda sidorna.
              
              
              
              
            
Granska och testa sidorna för att skapa och redigera kurser. Skapa en ny kurs. Avdelningen väljs av dess primära nyckel (ett heltal), inte dess namn. Redigera den nya kursen. När du är klar med testningen tar du bort den nya kursen.
Skapa en basklass för att dela gemensam kod
Sidorna Kurser/Skapa och Kurser/Redigera behöver var och en en lista med avdelningsnamn. Skapa basklassen Pages/Courses/DepartmentNamePageModel.cshtml.cs för sidorna Skapa och redigera:
using ContosoUniversity.Data;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.AspNetCore.Mvc.Rendering;
using Microsoft.EntityFrameworkCore;
using System.Linq;
namespace ContosoUniversity.Pages.Courses
{
    public class DepartmentNamePageModel : PageModel
    {
        public SelectList DepartmentNameSL { get; set; }
        public void PopulateDepartmentsDropDownList(SchoolContext _context,
            object selectedDepartment = null)
        {
            var departmentsQuery = from d in _context.Departments
                                   orderby d.Name // Sort by name.
                                   select d;
            DepartmentNameSL = new SelectList(departmentsQuery.AsNoTracking(),
                        "DepartmentID", "Name", selectedDepartment);
        }
    }
}
Föregående kod skapar en SelectList för att innehålla listan över avdelningsnamn. Parametern selectedDepartment gör att den anropande koden kan ange det objekt som ska väljas när listrutan återges. Men när du använder hjälpverktyget Välj tagg med asp-forbestäms det valda objektet av modellegenskapsvärdet (till exempel Course.DepartmentID), inte av parametern selectedDepartment .
Klasserna Skapa och redigera sidmodell härleds från DepartmentNamePageModel.
Anpassa kurssidorna
När en ny kursentitet skapas måste den ha en relation till en befintlig avdelning. Om du vill lägga till en avdelning när du skapar en kurs innehåller basklassen för Skapa och redigera en listruta för att välja avdelning. Listrutan ställer in Course.DepartmentID egenskapen främmande nyckel (FK). 
              EF Core använder FK:n Course.DepartmentID för att infoga navigeringsegenskap Department.
              
              
            
Uppdatera sidan Skapa modell med följande kod:
using ContosoUniversity.Models;
using Microsoft.AspNetCore.Mvc;
using System.Threading.Tasks;
namespace ContosoUniversity.Pages.Courses
{
    public class CreateModel : DepartmentNamePageModel
    {
        private readonly ContosoUniversity.Data.SchoolContext _context;
        public CreateModel(ContosoUniversity.Data.SchoolContext context)
        {
            _context = context;
        }
        public IActionResult OnGet()
        {
            PopulateDepartmentsDropDownList(_context);
            return Page();
        }
        [BindProperty]
        public Course Course { get; set; }
        public async Task<IActionResult> OnPostAsync()
        {
            if (!ModelState.IsValid)
            {
                return Page();
            }
            var emptyCourse = new Course();
            if (await TryUpdateModelAsync<Course>(
                 emptyCourse,
                 "course",   // Prefix for form value.
                 s => s.CourseID, s => s.DepartmentID, s => s.Title, s => s.Credits))
            {
                _context.Courses.Add(emptyCourse);
                await _context.SaveChangesAsync();
                return RedirectToPage("./Index");
            }
            // Repopulate departments dropdown. emptyCourse.DepartmentID determines the selected item.
            PopulateDepartmentsDropDownList(_context, emptyCourse.DepartmentID);
            return Page();
        }
      }
}
Föregående kod:
- Härleds från 
DepartmentNamePageModel. - Används 
TryUpdateModelAsyncför att förhindra överpublicering. - 
              
ViewData["DepartmentID"]Ersätter medDepartmentNameSL(från basklassen). 
              ViewData["DepartmentID"] ersätts med den starkt inskrivna DepartmentNameSL. Starkt skrivna modeller föredras framför svagt skrivna. Mer information finns i Svagt inskrivna data (ViewData och ViewBag).
Uppdatera sidan Skapa kurser
Uppdatera Pages/Courses/Create.cshtml med följande kod:
@page
@model ContosoUniversity.Pages.Courses.CreateModel
@{
    ViewData["Title"] = "Create Course";
}
<h2>Create</h2>
<h4>Course</h4>
<hr />
<div class="row">
    <div class="col-md-4">
        <form method="post">
            <div asp-validation-summary="ModelOnly" class="text-danger"></div>
            <div class="form-group">
                <label asp-for="Course.CourseID" class="control-label"></label>
                <input asp-for="Course.CourseID" class="form-control" />
                <span asp-validation-for="Course.CourseID" class="text-danger"></span>
            </div>
            <div class="form-group">
                <label asp-for="Course.Title" class="control-label"></label>
                <input asp-for="Course.Title" class="form-control" />
                <span asp-validation-for="Course.Title" class="text-danger"></span>
            </div>
            <div class="form-group">
                <label asp-for="Course.Credits" class="control-label"></label>
                <input asp-for="Course.Credits" class="form-control" />
                <span asp-validation-for="Course.Credits" class="text-danger"></span>
            </div>
            <div class="form-group">
                <label asp-for="Course.Department" class="control-label"></label>
                <select asp-for="Course.DepartmentID" class="form-control"
                        asp-items="@Model.DepartmentNameSL">
                    <option value="">-- Select Department --</option>
                </select>
                <span asp-validation-for="Course.DepartmentID" class="text-danger" />
            </div>
            <div class="form-group">
                <input type="submit" value="Create" class="btn btn-default" />
            </div>
        </form>
    </div>
</div>
<div>
    <a asp-page="Index">Back to List</a>
</div>
@section Scripts {
    @{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
}
Den föregående märkningen gör följande ändringar:
- Ändrar bildtexten från DepartmentID till Department.
 - 
              
"ViewBag.DepartmentID"Ersätter medDepartmentNameSL(från basklassen). - Lägger till alternativet "Välj avdelning". Den här ändringen renderar "Välj avdelning" i stället för den första avdelningen.
 - Lägger till ett valideringsmeddelande när avdelningen inte har valts.
 
Sidan Razor använder hjälpen Välj tagg:
<div class="form-group">
    <label asp-for="Course.Department" class="control-label"></label>
    <select asp-for="Course.DepartmentID" class="form-control"
            asp-items="@Model.DepartmentNameSL">
        <option value="">-- Select Department --</option>
    </select>
    <span asp-validation-for="Course.DepartmentID" class="text-danger" />
</div>
Testa Skapa-sidan. På sidan Skapa visas avdelningsnamnet i stället för avdelnings-ID:t.
Uppdatera sidan Redigera kurser.
Ersätt koden i Pages/Courses/Edit.cshtml.cs med följande kod:
using ContosoUniversity.Models;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using System.Threading.Tasks;
namespace ContosoUniversity.Pages.Courses
{
    public class EditModel : DepartmentNamePageModel
    {
        private readonly ContosoUniversity.Data.SchoolContext _context;
        public EditModel(ContosoUniversity.Data.SchoolContext context)
        {
            _context = context;
        }
        [BindProperty]
        public Course Course { get; set; }
        public async Task<IActionResult> OnGetAsync(int? id)
        {
            if (id == null)
            {
                return NotFound();
            }
            Course = await _context.Courses
                .Include(c => c.Department).FirstOrDefaultAsync(m => m.CourseID == id);
            if (Course == null)
            {
                return NotFound();
            }
            // Populate departments dropdown. Course.DepartmentID determines the selected item.
            PopulateDepartmentsDropDownList(_context,Course.DepartmentID);
            return Page();
        }
        public async Task<IActionResult> OnPostAsync(int? id)
        {
            if (!ModelState.IsValid)
            {
                return Page();
            }
            var courseToUpdate = await _context.Courses.FindAsync(id);
            if (await TryUpdateModelAsync<Course>(
                 courseToUpdate,
                 "course",   // Prefix for form value.
                   c => c.Credits, c => c.DepartmentID, c => c.Title))
            {
                await _context.SaveChangesAsync();
                return RedirectToPage("./Index");
            }
            // Repopulate departments dropdown. courseToUpdate.DepartmentID determines the selected item.
            PopulateDepartmentsDropDownList(_context, courseToUpdate.DepartmentID);
            return Page();
        }       
    }
}
Ändringarna liknar dem som gjordes i Skapa sidmodellen. I föregående kod PopulateDepartmentsDropDownList skickar du i avdelnings-ID:t. När du använder hjälpverktyget Välj tagg med asp-for="Course.DepartmentID"bestäms det markerade objektet i listrutan av Course.DepartmentIDvärdet för , inte av parametern selectedDepartment som skickas till konstruktorn SelectList.
Uppdatera Pages/Courses/Edit.cshtml med följande markering:
@page
@model ContosoUniversity.Pages.Courses.EditModel
@{
    ViewData["Title"] = "Edit";
}
<h2>Edit</h2>
<h4>Course</h4>
<hr />
<div class="row">
    <div class="col-md-4">
        <form method="post">
            <div asp-validation-summary="ModelOnly" class="text-danger"></div>
            <input type="hidden" asp-for="Course.CourseID" />
            <div class="form-group">
                <label asp-for="Course.CourseID" class="control-label"></label>
                <div>@Html.DisplayFor(model => model.Course.CourseID)</div>
            </div>
            <div class="form-group">
                <label asp-for="Course.Title" class="control-label"></label>
                <input asp-for="Course.Title" class="form-control" />
                <span asp-validation-for="Course.Title" class="text-danger"></span>
            </div>
            <div class="form-group">
                <label asp-for="Course.Credits" class="control-label"></label>
                <input asp-for="Course.Credits" class="form-control" />
                <span asp-validation-for="Course.Credits" class="text-danger"></span>
            </div>
            <div class="form-group">
                <label asp-for="Course.Department" class="control-label"></label>
                <select asp-for="Course.DepartmentID" class="form-control" 
                        asp-items="@Model.DepartmentNameSL"></select>
                <span asp-validation-for="Course.DepartmentID" class="text-danger"></span>
            </div>
            <div class="form-group">
                <input type="submit" value="Save" class="btn btn-default" />
            </div>
        </form>
    </div>
</div>
<div>
    <a asp-page="./Index">Back to List</a>
</div>
@section Scripts {
    @{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
}
Den föregående märkningen gör följande ändringar:
- Visar kurs-ID. Vanligtvis visas inte primärnyckeln (PK) för en entitet. PK:er är vanligtvis meningslösa för användarna. I det här fallet är PK:t kursnumret.
 - Ändrar bildtexten från DepartmentID till Department.
 - 
              
"ViewBag.DepartmentID"Ersätter medDepartmentNameSL(från basklassen). 
Sidan innehåller ett dolt fält (<input type="hidden">) för kursnumret. Att lägga till en <label> tag helper med asp-for="Course.CourseID" eliminerar inte behovet av det dolda fältet. 
              <input type="hidden"> krävs för att kursnumret ska inkluderas i de publicerade data när användaren klickar på Spara.
Testa den uppdaterade koden. Skapa, redigera och ta bort en kurs.
Lägg till AsNoTracking i sidmodellerna Detaljer och Ta bort
              AsNoTracking kan förbättra prestanda när spårning inte krävs. Lägg till AsNoTracking i sidmodellen för Ta bort och Detaljer. Följande kod visar den uppdaterade borttagningssidans modell:
public class DeleteModel : PageModel
{
    private readonly ContosoUniversity.Data.SchoolContext _context;
    public DeleteModel(ContosoUniversity.Data.SchoolContext context)
    {
        _context = context;
    }
    [BindProperty]
    public Course Course { get; set; }
    public async Task<IActionResult> OnGetAsync(int? id)
    {
        if (id == null)
        {
            return NotFound();
        }
        Course = await _context.Courses
            .AsNoTracking()
            .Include(c => c.Department)
            .FirstOrDefaultAsync(m => m.CourseID == id);
        if (Course == null)
        {
            return NotFound();
        }
        return Page();
    }
    public async Task<IActionResult> OnPostAsync(int? id)
    {
        if (id == null)
        {
            return NotFound();
        }
        Course = await _context.Courses
            .AsNoTracking()
            .FirstOrDefaultAsync(m => m.CourseID == id);
        if (Course != null)
        {
            _context.Courses.Remove(Course);
            await _context.SaveChangesAsync();
        }
        return RedirectToPage("./Index");
    }
}
              OnGetAsync Uppdatera metoden i Pages/Courses/Details.cshtml.cs filen:
public async Task<IActionResult> OnGetAsync(int? id)
{
    if (id == null)
    {
        return NotFound();
    }
    Course = await _context.Courses
         .AsNoTracking()
         .Include(c => c.Department)
         .FirstOrDefaultAsync(m => m.CourseID == id);
    if (Course == null)
    {
        return NotFound();
    }
    return Page();
}
Ändra sidorna Ta bort och Information
Uppdatera sidan Ta bort Razor med följande markering:
@page
@model ContosoUniversity.Pages.Courses.DeleteModel
@{
    ViewData["Title"] = "Delete";
}
<h2>Delete</h2>
<h3>Are you sure you want to delete this?</h3>
<div>
    <h4>Course</h4>
    <hr />
    <dl class="dl-horizontal">
        <dt>
            @Html.DisplayNameFor(model => model.Course.CourseID)
        </dt>
        <dd>
            @Html.DisplayFor(model => model.Course.CourseID)
        </dd>
        <dt>
            @Html.DisplayNameFor(model => model.Course.Title)
        </dt>
        <dd>
            @Html.DisplayFor(model => model.Course.Title)
        </dd>
        <dt>
            @Html.DisplayNameFor(model => model.Course.Credits)
        </dt>
        <dd>
            @Html.DisplayFor(model => model.Course.Credits)
        </dd>
        <dt>
            @Html.DisplayNameFor(model => model.Course.Department)
        </dt>
        <dd>
            @Html.DisplayFor(model => model.Course.Department.DepartmentID)
        </dd>
    </dl>
    
    <form method="post">
        <input type="hidden" asp-for="Course.CourseID" />
        <input type="submit" value="Delete" class="btn btn-default" /> |
        <a asp-page="./Index">Back to List</a>
    </form>
</div>
Gör samma ändringar på sidan Information.
Testa kursens sidor
Testa skapa, redigera, detaljer och ta bort.
Uppdatera lärarsidorna
Följande avsnitt uppdaterar lärarsidorna.
Lägg till kontorsplats
När du redigerar en instruktörspost kanske du vill uppdatera instruktörens kontorsuppgift. Entiteten Instructor har en en-till-noll-eller-en-relation med entiteten OfficeAssignment . Lärarkoden måste hantera:
- Om användaren rensar tilldelningen för kontoret, ta bort 
OfficeAssignment-entiteten. - Om användaren anger en kontorstilldelning och den var tom, ska en ny 
OfficeAssignmententitet skapas. - Om användaren ändrar kontortilldelningen, uppdatera entiteten 
OfficeAssignment. 
Uppdatera instruktörens redigeringssidmodell med följande kod:
public class EditModel : PageModel
{
    private readonly ContosoUniversity.Data.SchoolContext _context;
    public EditModel(ContosoUniversity.Data.SchoolContext context)
    {
        _context = context;
    }
    [BindProperty]
    public Instructor Instructor { get; set; }
    public async Task<IActionResult> OnGetAsync(int? id)
    {
        if (id == null)
        {
            return NotFound();
        }
        Instructor = await _context.Instructors
            .Include(i => i.OfficeAssignment)
            .AsNoTracking()
            .FirstOrDefaultAsync(m => m.ID == id);
        if (Instructor == null)
        {
            return NotFound();
        }
        return Page();
    }
    public async Task<IActionResult> OnPostAsync(int? id)
    {
        if (!ModelState.IsValid)
        {
            return Page();
        }
        var instructorToUpdate = await _context.Instructors
            .Include(i => i.OfficeAssignment)
            .FirstOrDefaultAsync(s => s.ID == id);
        if (await TryUpdateModelAsync<Instructor>(
            instructorToUpdate,
            "Instructor",
            i => i.FirstMidName, i => i.LastName, 
            i => i.HireDate, i => i.OfficeAssignment))
        {
            if (String.IsNullOrWhiteSpace(
                instructorToUpdate.OfficeAssignment?.Location))
            {
                instructorToUpdate.OfficeAssignment = null;
            }
            await _context.SaveChangesAsync();
        }
        return RedirectToPage("./Index");
    }
}
Föregående kod:
- Hämtar den aktuella 
Instructorentiteten från databasen med ivrig inläsning för navigeringsegenskapenOfficeAssignment. - Uppdaterar den hämtade entiteten 
Instructormed värden från modellbindaren.TryUpdateModelförhindrar överpublicering. - Om kontorsplatsen är tom anger du 
Instructor.OfficeAssignmenttill null. NärInstructor.OfficeAssignmentär null tas den relaterade raden iOfficeAssignmenttabellen bort. 
Uppdatera redigeringssidan för lärare
Uppdatera Pages/Instructors/Edit.cshtml med kontorsplatsen:
@page
@model ContosoUniversity.Pages.Instructors.EditModel
@{
    ViewData["Title"] = "Edit";
}
<h2>Edit</h2>
<h4>Instructor</h4>
<hr />
<div class="row">
    <div class="col-md-4">
        <form method="post">
            <div asp-validation-summary="ModelOnly" class="text-danger"></div>
            <input type="hidden" asp-for="Instructor.ID" />
            <div class="form-group">
                <label asp-for="Instructor.LastName" class="control-label"></label>
                <input asp-for="Instructor.LastName" class="form-control" />
                <span asp-validation-for="Instructor.LastName" class="text-danger"></span>
            </div>
            <div class="form-group">
                <label asp-for="Instructor.FirstMidName" class="control-label"></label>
                <input asp-for="Instructor.FirstMidName" class="form-control" />
                <span asp-validation-for="Instructor.FirstMidName" class="text-danger"></span>
            </div>
            <div class="form-group">
                <label asp-for="Instructor.HireDate" class="control-label"></label>
                <input asp-for="Instructor.HireDate" class="form-control" />
                <span asp-validation-for="Instructor.HireDate" class="text-danger"></span>
            </div>
            <div class="form-group">
                <label asp-for="Instructor.OfficeAssignment.Location" class="control-label"></label>
                <input asp-for="Instructor.OfficeAssignment.Location" class="form-control" />
                <span asp-validation-for="Instructor.OfficeAssignment.Location" class="text-danger" />
            </div>
            <div class="form-group">
                <input type="submit" value="Save" class="btn btn-default" />
            </div>
        </form>
    </div>
</div>
<div>
    <a asp-page="./Index">Back to List</a>
</div>
@section Scripts {
    @{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
}
Kontrollera att du kan ändra en instruktörs kontorsplats.
Lägga till kurstilldelningar på redigeringssidan för lärare
Instruktörer kan undervisa valfritt antal kurser. I det här avsnittet lägger du till möjligheten att ändra kurstilldelningar. Följande bild visar den uppdaterade redigeringssidan för lärare:
              
              
            
              Course och Instructor har en många-till-många-relation. Om du vill lägga till och ta bort relationer lägger du till och tar bort entiteter från anslutningsentitetsuppsättningen CourseAssignments .
med kryssrutor kan ändringar göras i kurser som en instruktör har tilldelats. En kryssruta visas för varje kurs i databasen. Kurser som instruktören har tilldelats kontrolleras. Användaren kan markera eller avmarkera kryssrutor för att ändra kurstilldelningar. Om antalet kurser var mycket större:
- Du skulle förmodligen använda ett annat användargränssnitt för att visa kurserna.
 - Metoden för att manipulera en kopplingsentitet för att skapa eller ta bort relationer skulle inte ändras.
 
Lägg till klasser för att stödja skapa- och redigeringssidor för instruktörer
Skapa Models/SchoolViewModels/AssignedCourseData.cs med följande kod:
namespace ContosoUniversity.Models.SchoolViewModels
{
    public class AssignedCourseData
    {
        public int CourseID { get; set; }
        public string Title { get; set; }
        public bool Assigned { get; set; }
    }
}
Klassen AssignedCourseData innehåller data för att skapa kryssrutorna för tilldelade kurser av en lärare.
Skapa basklassen Pages/Instructors/InstructorCoursesPageModel.cshtml.cs :
using ContosoUniversity.Data;
using ContosoUniversity.Models;
using ContosoUniversity.Models.SchoolViewModels;
using Microsoft.AspNetCore.Mvc.RazorPages;
using System.Collections.Generic;
using System.Linq;
namespace ContosoUniversity.Pages.Instructors
{
    public class InstructorCoursesPageModel : PageModel
    {
        public List<AssignedCourseData> AssignedCourseDataList;
        public void PopulateAssignedCourseData(SchoolContext context, 
                                               Instructor instructor)
        {
            var allCourses = context.Courses;
            var instructorCourses = new HashSet<int>(
                instructor.CourseAssignments.Select(c => c.CourseID));
            AssignedCourseDataList = new List<AssignedCourseData>();
            foreach (var course in allCourses)
            {
                AssignedCourseDataList.Add(new AssignedCourseData
                {
                    CourseID = course.CourseID,
                    Title = course.Title,
                    Assigned = instructorCourses.Contains(course.CourseID)
                });
            }
        }
        public void UpdateInstructorCourses(SchoolContext context, 
            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
                                .SingleOrDefault(i => i.CourseID == course.CourseID);
                        context.Remove(courseToRemove);
                    }
                }
            }
        }
    }
}
              InstructorCoursesPageModel är den basklass som du ska använda för sidmodellerna Redigera och Skapa. 
              PopulateAssignedCourseData läser alla Course entiteter för att fylla i AssignedCourseDataList. För varje kurs anger CourseID koden, rubriken och om läraren är tilldelad till kursen eller inte. En HashSet används för att skapa effektiva sökningar.
Redigera sidmodell för lärare
Uppdatera instruktörens Redigera-sidmodell med följande kod:
public class EditModel : InstructorCoursesPageModel
{
    private readonly ContosoUniversity.Data.SchoolContext _context;
    public EditModel(ContosoUniversity.Data.SchoolContext context)
    {
        _context = context;
    }
    [BindProperty]
    public Instructor Instructor { get; set; }
    public async Task<IActionResult> OnGetAsync(int? id)
    {
        if (id == null)
        {
            return NotFound();
        }
        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(_context, Instructor);
        return Page();
    }
    public async Task<IActionResult> OnPostAsync(int? id, string[] selectedCourses)
    {
        if (!ModelState.IsValid)
        {
            return Page();
        }
        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,
            "Instructor",
            i => i.FirstMidName, i => i.LastName,
            i => i.HireDate, i => i.OfficeAssignment))
        {
            if (String.IsNullOrWhiteSpace(
                instructorToUpdate.OfficeAssignment?.Location))
            {
                instructorToUpdate.OfficeAssignment = null;
            }
            UpdateInstructorCourses(_context, selectedCourses, instructorToUpdate);
            await _context.SaveChangesAsync();
            return RedirectToPage("./Index");
        }
        UpdateInstructorCourses(_context, selectedCourses, instructorToUpdate);
        PopulateAssignedCourseData(_context, instructorToUpdate);
        return Page();
    }
}
Den föregående koden hanterar ändringar i kontorstilldelning.
Uppdatera instruktörsvyn Razor :
@page
@model ContosoUniversity.Pages.Instructors.EditModel
@{
    ViewData["Title"] = "Edit";
}
<h2>Edit</h2>
<h4>Instructor</h4>
<hr />
<div class="row">
    <div class="col-md-4">
        <form method="post">
            <div asp-validation-summary="ModelOnly" class="text-danger"></div>
            <input type="hidden" asp-for="Instructor.ID" />
            <div class="form-group">
                <label asp-for="Instructor.LastName" class="control-label"></label>
                <input asp-for="Instructor.LastName" class="form-control" />
                <span asp-validation-for="Instructor.LastName" class="text-danger"></span>
            </div>
            <div class="form-group">
                <label asp-for="Instructor.FirstMidName" class="control-label"></label>
                <input asp-for="Instructor.FirstMidName" class="form-control" />
                <span asp-validation-for="Instructor.FirstMidName" class="text-danger"></span>
            </div>
            <div class="form-group">
                <label asp-for="Instructor.HireDate" class="control-label"></label>
                <input asp-for="Instructor.HireDate" class="form-control" />
                <span asp-validation-for="Instructor.HireDate" class="text-danger"></span>
            </div>
            <div class="form-group">
                <label asp-for="Instructor.OfficeAssignment.Location" class="control-label"></label>
                <input asp-for="Instructor.OfficeAssignment.Location" class="form-control" />
                <span asp-validation-for="Instructor.OfficeAssignment.Location" class="text-danger" />
            </div>
            <div class="form-group">
                <div class="col-md-offset-2 col-md-10">
                    <table>
                        <tr>
                            @{
                                int cnt = 0;
                                foreach (var course in Model.AssignedCourseDataList)
                                {
                                    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>
            <div class="form-group">
                <input type="submit" value="Save" class="btn btn-default" />
            </div>
        </form>
    </div>
</div>
<div>
    <a asp-page="./Index">Back to List</a>
</div>
@section Scripts {
    @{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
}
Note
När du klistrar in koden i Visual Studio ändras radbrytningar på ett sätt som bryter koden. Tryck på Ctrl +Z en gång för att ångra den automatiska formateringen. Ctrl+Z åtgärdar radbrytningarna så att de ser ut som det du ser här. Indraget behöver inte vara perfekt, men raderna @:</tr><tr>, @:<td>, @:</td> och @:</tr> måste vara på en enda rad, som visas. När blocket med ny kod är markerat trycker du på Tabb tre gånger för att rada upp den nya koden med den befintliga koden. Rösta på eller granska statusen för den här buggen med den här länken.
Föregående kod skapar en HTML-tabell som har tre kolumner. Varje kolumn har en kryssruta och en bildtext som innehåller kursnummer och rubrik. Kryssrutorna har samma namn ("selectedCourses"). Med samma namn informerar man modellbindaren om att behandla dem som en grupp. Värdeattributet för varje kryssruta är inställt på CourseID. När sidan publiceras skickar modellbindaren en matris som endast består av CourseID värden för de markerade kryssrutorna.
När kryssrutorna återges initialt har kurser som tilldelats instruktören markerade attribut.
Kör appen och testa den uppdaterade sidan Redigera lärare. Ändra vissa kurstilldelningar. Ändringarna återspeglas på sidan Index.
Obs! Den metod som används här för att redigera lärarkursdata fungerar bra när det finns ett begränsat antal kurser. För samlingar som är mycket större skulle ett annat användargränssnitt och en annan uppdateringsmetod vara mer användbara och effektiva.
Uppdatera instruktörssidan Skapa
Uppdatera instruktörens CreatePage-modell med följande kod:
using ContosoUniversity.Models;
using Microsoft.AspNetCore.Mvc;
using System.Collections.Generic;
using System.Threading.Tasks;
namespace ContosoUniversity.Pages.Instructors
{
    public class CreateModel : InstructorCoursesPageModel
    {
        private readonly ContosoUniversity.Data.SchoolContext _context;
        public CreateModel(ContosoUniversity.Data.SchoolContext context)
        {
            _context = context;
        }
        public IActionResult OnGet()
        {
            var instructor = new Instructor();
            instructor.CourseAssignments = new List<CourseAssignment>();
            // Provides an empty collection for the foreach loop
            // foreach (var course in Model.AssignedCourseDataList)
            // in the Create Razor page.
            PopulateAssignedCourseData(_context, instructor);
            return Page();
        }
        [BindProperty]
        public Instructor Instructor { get; set; }
        public async Task<IActionResult> OnPostAsync(string[] selectedCourses)
        {
            if (!ModelState.IsValid)
            {
                return Page();
            }
            var newInstructor = new Instructor();
            if (selectedCourses != null)
            {
                newInstructor.CourseAssignments = new List<CourseAssignment>();
                foreach (var course in selectedCourses)
                {
                    var courseToAdd = new CourseAssignment
                    {
                        CourseID = int.Parse(course)
                    };
                    newInstructor.CourseAssignments.Add(courseToAdd);
                }
            }
            if (await TryUpdateModelAsync<Instructor>(
                newInstructor,
                "Instructor",
                i => i.FirstMidName, i => i.LastName,
                i => i.HireDate, i => i.OfficeAssignment))
            {
                _context.Instructors.Add(newInstructor);                
                await _context.SaveChangesAsync();
                return RedirectToPage("./Index");
            }
            PopulateAssignedCourseData(_context, newInstructor);
            return Page();
        }
    }
}
Föregående kod liknar Pages/Instructors/Edit.cshtml.cs koden.
Uppdatera instruktör Skapa Razor sidan med följande markupkod:
@page
@model ContosoUniversity.Pages.Instructors.CreateModel
@{
    ViewData["Title"] = "Create";
}
<h2>Create</h2>
<h4>Instructor</h4>
<hr />
<div class="row">
    <div class="col-md-4">
        <form method="post">
            <div asp-validation-summary="ModelOnly" class="text-danger"></div>
            <div class="form-group">
                <label asp-for="Instructor.LastName" class="control-label"></label>
                <input asp-for="Instructor.LastName" class="form-control" />
                <span asp-validation-for="Instructor.LastName" class="text-danger"></span>
            </div>
            <div class="form-group">
                <label asp-for="Instructor.FirstMidName" class="control-label"></label>
                <input asp-for="Instructor.FirstMidName" class="form-control" />
                <span asp-validation-for="Instructor.FirstMidName" class="text-danger"></span>
            </div>
            <div class="form-group">
                <label asp-for="Instructor.HireDate" class="control-label"></label>
                <input asp-for="Instructor.HireDate" class="form-control" />
                <span asp-validation-for="Instructor.HireDate" class="text-danger"></span>
            </div>
            
            <div class="form-group">
                <label asp-for="Instructor.OfficeAssignment.Location" class="control-label"></label>
                <input asp-for="Instructor.OfficeAssignment.Location" class="form-control" />
                <span asp-validation-for="Instructor.OfficeAssignment.Location" class="text-danger" />
            </div>
            <div class="form-group">
                <div class="col-md-offset-2 col-md-10">
                    <table>
                        <tr>
                            @{
                                int cnt = 0;
                                foreach (var course in Model.AssignedCourseDataList)
                                {
                                    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>
            <div class="form-group">
                <input type="submit" value="Create" class="btn btn-default" />
            </div>
        </form>
    </div>
</div>
<div>
    <a asp-page="Index">Back to List</a>
</div>
@section Scripts {
    @{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
}
Testa sidan Skapa för instruktör.
Uppdatera sidan Ta bort
Uppdatera borttagningssidans modell med följande kod:
using ContosoUniversity.Models;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.EntityFrameworkCore;
using System.Linq;
using System.Threading.Tasks;
namespace ContosoUniversity.Pages.Instructors
{
    public class DeleteModel : PageModel
    {
        private readonly ContosoUniversity.Data.SchoolContext _context;
        public DeleteModel(ContosoUniversity.Data.SchoolContext context)
        {
            _context = context;
        }
        [BindProperty]
        public Instructor Instructor { get; set; }
        public async Task<IActionResult> OnGetAsync(int? id)
        {
            if (id == null)
            {
                return NotFound();
            }
            Instructor = await _context.Instructors.SingleAsync(m => m.ID == id);
            if (Instructor == null)
            {
                return NotFound();
            }
            return Page();
        }
        public async Task<IActionResult> OnPostAsync(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 RedirectToPage("./Index");
        }
    }
}
Föregående kod gör följande ändringar:
Använder ivrig inläsning för navigeringsegenskapen
CourseAssignments.CourseAssignmentsmåste inkluderas eller så tas de inte bort när instruktören tas bort. Om du vill undvika att behöva läsa dem konfigurerar du kaskadborttagning i databasen.Om instruktören som ska tas bort tilldelas som administratör för några avdelningar tar du bort lärartilldelningen från dessa avdelningar.
Ytterligare resurser
ASP.NET Core