Část 7, Razor Stránky s EF Core v ASP.NET Core – aktualizace souvisejících dat
Tom Dykstra, Jon P Smith a Rick Anderson
Webová aplikace Contoso University ukazuje, jak vytvářet Razor webové aplikace Pages pomocí EF Core sady Visual Studio. Informace o sérii kurzů najdete v prvním kurzu.
Pokud narazíte na problémy, které nemůžete vyřešit, stáhněte si dokončenou aplikaci a porovnejte tento kód s tím, co jste vytvořili podle kurzu.
V tomto kurzu se dozvíte, jak aktualizovat související data. Následující ilustrace znázorňují některé dokončené stránky.
Aktualizace stránek Pro vytvoření a úpravy kurzu
Vygenerovaný kód pro stránky Vytvoření a úpravy kurzu obsahuje rozevírací seznam Oddělení, který zobrazuje DepartmentID
, an int
. V rozevíracím seznamu by se měl zobrazit název oddělení, takže obě tyto stránky potřebují seznam názvů oddělení. Chcete-li poskytnout tento seznam, použijte základní třídu pro stránky Vytvořit a upravit.
Vytvoření základní třídy pro vytvoření a úpravy kurzu
Vytvořte Pages/Courses/DepartmentNamePageModel.cs
soubor s následujícím kódem:
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);
}
}
}
Předchozí kód vytvoří seznam SelectList názvů oddělení. Je-li selectedDepartment
zadáno, je toto oddělení vybráno v sadě SelectList
.
Třídy modelu vytvoření a úpravy stránky budou odvozeny z DepartmentNamePageModel
.
Aktualizace modelu stránky Vytvoření kurzu
Kurz je přiřazen k oddělení. Základní třída pro stránky Vytvořit a Upravit poskytuje SelectList
pro výběr oddělení. Rozevírací seznam, který používá SelectList
vlastnost cizího Course.DepartmentID
klíče (FK). EF CoreCourse.DepartmentID
používá jazyk FK k načtení Department
navigační vlastnosti.
Aktualizujte Pages/Courses/Create.cshtml.cs
následujícím kódem:
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");
}
// Select DepartmentID if TryUpdateModelAsync fails.
PopulateDepartmentsDropDownList(_context, emptyCourse.DepartmentID);
return Page();
}
}
}
Pokud chcete zobrazit komentáře ke kódu přeložené do jiných jazyků, než je angličtina, dejte nám vědět v této diskuzi na GitHubu.
Předchozí kód:
- Odvozuje z
DepartmentNamePageModel
. - Slouží TryUpdateModelAsync k zabránění nadměrnému umístění.
- Odebere
ViewData["DepartmentID"]
. Jedná seDepartmentNameSL
SelectList
o model silného typu a bude používán stránkou Razor . Modely silného typu jsou upřednostňované před slabě typovanými modely. Další informace naleznete v tématu Slabě typovaná data (ViewData a ViewBag).
Aktualizace stránky Vytvoření Razor kurzu
Aktualizujte Pages/Courses/Create.cshtml
následujícím kódem:
@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");}
}
Předchozí kód provede následující změny:
- Změní titulek z DepartmentID na Department.
"ViewBag.DepartmentID"
Nahradí zaDepartmentNameSL
(ze základní třídy).- Přidá možnost Vybrat oddělení. Tato změna v rozevíracím seznamu vykreslí možnost Vybrat oddělení, pokud ještě není vybráno žádné oddělení, a ne v prvním oddělení.
- Přidá ověřovací zprávu, když oddělení není vybrané.
Stránka Razor používá pomocníka pro výběr značek:
<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>
Otestujte stránku Vytvořit. Na stránce Vytvořit se místo ID oddělení zobrazí název oddělení.
Aktualizace modelu stránky Upravit kurz
Aktualizujte Pages/Courses/Edit.cshtml.cs
následujícím kódem:
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();
}
// Select current DepartmentID.
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");
}
// Select DepartmentID if TryUpdateModelAsync fails.
PopulateDepartmentsDropDownList(_context, courseToUpdate.DepartmentID);
return Page();
}
}
}
Změny se podobají změnám provedeným v modelu vytvořit stránku. V předchozím kódu PopulateDepartmentsDropDownList
předá ID oddělení, které toto oddělení vybere v rozevíracím seznamu.
Aktualizace stránky Upravit Razor kurz
Aktualizujte Pages/Courses/Edit.cshtml
následujícím kódem:
@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");}
}
Předchozí kód provede následující změny:
- Zobrazí ID kurzu. Obecně se nezobrazuje primární klíč (PK) entity. Sady PKS jsou obvykle pro uživatele nesmyslné. V tomto případě je PK číslo kurzu.
- Změní titulek rozevíracího seznamu Oddělení z ID oddělení na Oddělení.
"ViewBag.DepartmentID"
DepartmentNameSL
Nahradí třídou , která je v základní třídě.
Stránka obsahuje skryté pole (<input type="hidden">
) pro číslo kurzu. <label>
Přidání pomocné rutiny asp-for="Course.CourseID"
značek neodstraní potřebu skrytého pole. <input type="hidden">
je vyžadováno, aby číslo kurzu bylo zahrnuto do odeslaných dat, když uživatel vybere Možnost Uložit.
Aktualizace modelů stránek kurzu
AsNoTracking může zvýšit výkon, pokud sledování není vyžadováno.
Aktualizujte Pages/Courses/Delete.cshtml.cs
a Pages/Courses/Details.cshtml.cs
přidejte AsNoTracking
do OnGetAsync
metod:
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();
}
Aktualizace stránek kurzu Razor
Aktualizujte Pages/Courses/Delete.cshtml
následujícím kódem:
@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>
Proveďte stejné změny na stránce Podrobnosti.
@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>
Testování stránek kurzu
Otestujte stránky pro vytvoření, úpravy, podrobnosti a odstranění.
Aktualizace stránek pro vytváření a úpravy instruktora
Instruktori mohou učit libovolný počet kurzů. Následující obrázek ukazuje stránku pro úpravy instruktora s polem zaškrtávacích políček kurzu.
Zaškrtávací políčka umožňují změny kurzů, ke kterým je instruktor přiřazený. Zaškrtávací políčko se zobrazí pro každý kurz v databázi. Jsou vybrány kurzy, ke kterým je instruktor přiřazený. Uživatel může zaškrtnutím nebo zrušením zaškrtnutí políček změnit zadání kurzu. Pokud byl počet kurzů mnohem větší, může lepší fungovat jiné uživatelské rozhraní. Metoda správy relace M:N se zde ale nezměnila. Pokud chcete vytvořit nebo odstranit relace, manipulujete s entitou spojení.
Vytvoření třídy pro přiřazená data kurzů
Vytvořte Models/SchoolViewModels/AssignedCourseData.cs
pomocí následujícího kódu:
namespace ContosoUniversity.Models.SchoolViewModels
{
public class AssignedCourseData
{
public int CourseID { get; set; }
public string Title { get; set; }
public bool Assigned { get; set; }
}
}
Třída AssignedCourseData
obsahuje data pro vytvoření zaškrtávacích políček pro kurzy přiřazené instruktorovi.
Vytvoření základní třídy modelu stránky instruktora
Pages/Instructors/InstructorCoursesPageModel.cs
Vytvořte základní třídu:
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)
});
}
}
}
}
Je InstructorCoursesPageModel
základní třídou pro modely stránek Edit a Create. PopulateAssignedCourseData
přečte všechny Course
entity, které se mají naplnit AssignedCourseDataList
. Pro každý kurz kód nastaví CourseID
, titul a zda je instruktor přiřazen k kurzu. Sada hash se používá k efektivnímu vyhledávání.
Zpracování umístění kanceláře
Další relací, kterou musí stránka pro úpravy zpracovat, je relace 1:0 nebo 1, kterou má entita Instruktor s entitou OfficeAssignment
. Kód pro úpravy instruktora musí zpracovávat následující scénáře:
- Pokud uživatel vymaže přiřazení kanceláře, odstraňte entitu
OfficeAssignment
. - Pokud uživatel zadá přiřazení kanceláře a bude prázdný, vytvořte novou
OfficeAssignment
entitu. - Pokud uživatel změní přiřazení kanceláře, aktualizujte entitu
OfficeAssignment
.
Aktualizace modelu stránky Pro úpravy instruktora
Aktualizujte Pages/Instructors/Edit.cshtml.cs
následujícím kódem:
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);
}
}
}
}
}
}
Předchozí kód:
- Získá aktuální
Instructor
entitu z databáze pomocí dychtivého načítání proOfficeAssignment
vlastnosti navigace aCourses
vlastnosti navigace. - Aktualizuje načtenou
Instructor
entitu hodnotami z pořadače modelu. TryUpdateModelAsync zabraňuje nadměrnému umístění. - Pokud je umístění kanceláře prázdné, nastaví
Instructor.OfficeAssignment
se na hodnotu null. PokudInstructor.OfficeAssignment
je null, související řádek vOfficeAssignment
tabulce se odstraní. - Volání
PopulateAssignedCourseData
za účelem poskytnutí informací o zaškrtávacích polících pomocíAssignedCourseData
třídyOnGetAsync
modelu zobrazení OnPostAsync
VoláníUpdateInstructorCourses
, která použijí informace z zaškrtávacích políček na entitu instruktora, která se upravuje.- Volání
PopulateAssignedCourseData
aUpdateInstructorCourses
přihlášeníOnPostAsync
, pokud TryUpdateModelAsync selže. Tato metoda volá obnovení přiřazených dat kurzu zadaných na stránce při opětovném zobrazení s chybovou zprávou.
Razor Vzhledem k tomu, že stránka neobsahuje kolekci entit kurzu, pořadač modelů nemůže automaticky aktualizovat Courses
navigační vlastnost. Místo použití pořadače modelu k aktualizaci Courses
navigační vlastnosti, která je provedena v nové UpdateInstructorCourses
metodě. Proto je nutné vlastnost vyloučit Courses
z vazby modelu. To nevyžaduje žádnou změnu kódu, který volá TryUpdateModelAsync , protože používáte přetížení s deklarovanými vlastnostmi a Courses
není v seznamu zahrnutí.
Pokud nebyla vybrána žádná zaškrtávací políčka, kód inicializuje UpdateInstructorCourses
prázdnou instructorToUpdate.Courses
kolekci a vrátí:
if (selectedCourses == null)
{
instructorToUpdate.Courses = new List<Course>();
return;
}
Kód pak projde všemi kurzy v databázi a zkontroluje každý kurz proti kurzům, které jsou aktuálně přiřazené instruktorovi, a ty, které byly vybrány na stránce. Pro usnadnění efektivního vyhledávání jsou tyto dvě kolekce uloženy v HashSet
objektech.
Pokud je zaškrtnuté políčko pro kurz, ale kurz není v Instructor.Courses
navigační vlastnosti, kurz se přidá do kolekce v navigační vlastnosti.
if (selectedCoursesHS.Contains(course.CourseID.ToString()))
{
if (!instructorCourses.Contains(course.CourseID))
{
instructorToUpdate.Courses.Add(course);
}
}
Pokud není zaškrtnuté políčko pro kurz, ale kurz je v Instructor.Courses
navigační vlastnosti, kurz se z navigační vlastnosti odebere.
else
{
if (instructorCourses.Contains(course.CourseID))
{
var courseToRemove = instructorToUpdate.Courses.Single(
c => c.CourseID == course.CourseID);
instructorToUpdate.Courses.Remove(courseToRemove);
}
}
Aktualizace stránky Pro úpravy Razor instruktora
Aktualizujte Pages/Instructors/Edit.cshtml
následujícím kódem:
@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");}
}
Předchozí kód vytvoří tabulku HTML se třemi sloupci. Každý sloupec má zaškrtávací políčko a titulek obsahující číslo a název kurzu. Všechna zaškrtávací políčka mají stejný název ("selectedCourses"). Použití stejného názvu informuje pořadač modelu, aby s nimi zacházal jako se skupinou. Atribut hodnoty každého zaškrtávacího políčka je nastaven na CourseID
hodnotu . Když se stránka publikuje, pořadač modelu předá pole, které se skládá z CourseID
hodnot pouze pro zaškrtnutá políčka.
Po počátečním vykreslení zaškrtávacích políček se vyberou kurzy přiřazené instruktorovi.
Poznámka: Přístup k úpravě dat kurzu instruktora funguje dobře, když existuje omezený počet kurzů. U kolekcí, které jsou mnohem větší, by bylo vhodnější a efektivnější použít jiné uživatelské rozhraní a jinou metodu aktualizace.
Spusťte aplikaci a otestujte aktualizovanou stránku Pro úpravy instruktorů. Změňte některá zadání kurzu. Změny se projeví na stránce rejstříku.
Aktualizace stránky Pro vytvoření instruktora
Aktualizujte model stránky Pro vytvoření instruktora a kód podobný stránce Upravit:
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();
}
}
}
Předchozí kód:
Přidá protokolování pro upozornění a chybové zprávy.
Volání Load, která načte všechny kurzy v jednom databázovém volání. U malých kolekcí se jedná o optimalizaci při použití FindAsync.
FindAsync
vrátí sledovaný entitu bez požadavku na databázi.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)
vytvoří novouInstructor
relaci M :N bez explicitního mapování tabulky spojení. V EF 5.0 bylo přidáno M:N.
Otestujte stránku pro vytvoření instruktora.
Aktualizujte stránku Pro vytvoření Razor instruktora pomocí kódu podobného stránce Upravit:
@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");}
}
Aktualizace stránky Pro odstranění instruktora
Aktualizujte Pages/Instructors/Delete.cshtml.cs
následujícím kódem:
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");
}
}
}
Předchozí kód provede následující změny:
Používá dychtivé načítání pro
Courses
navigační vlastnost.Courses
musí být zahrnuté nebo se při odstranění instruktora neodstraní. Abyste se vyhnuli nutnosti je číst, nakonfigurujte kaskádové odstranění v databázi.Pokud je instruktor, který se má odstranit, přiřazený jako správce oddělení, odebere zadání instruktora z těchto oddělení.
Spusťte aplikaci a otestujte stránku Odstranit.
Další kroky
V tomto kurzu se dozvíte, jak aktualizovat související data. Následující ilustrace znázorňují některé dokončené stránky.
Aktualizace stránek Pro vytvoření a úpravy kurzu
Vygenerovaný kód pro stránky Vytvoření a úpravy kurzu obsahuje rozevírací seznam Oddělení, který zobrazuje ID oddělení (celé číslo). V rozevíracím seznamu by se měl zobrazit název oddělení, takže obě tyto stránky potřebují seznam názvů oddělení. Chcete-li poskytnout tento seznam, použijte základní třídu pro stránky Vytvořit a upravit.
Vytvoření základní třídy pro vytvoření a úpravy kurzu
Vytvořte Pages/Courses/DepartmentNamePageModel.cs
soubor s následujícím kódem:
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);
}
}
}
Předchozí kód vytvoří seznam SelectList názvů oddělení. Je-li selectedDepartment
zadáno, je toto oddělení vybráno v sadě SelectList
.
Třídy modelu vytvoření a úpravy stránky budou odvozeny z DepartmentNamePageModel
.
Aktualizace modelu stránky Vytvoření kurzu
Kurz je přiřazen k oddělení. Základní třída pro stránky Vytvořit a Upravit poskytuje SelectList
pro výběr oddělení. Rozevírací seznam, který používá SelectList
vlastnost cizího Course.DepartmentID
klíče (FK). EF CoreCourse.DepartmentID
používá jazyk FK k načtení Department
navigační vlastnosti.
Aktualizujte Pages/Courses/Create.cshtml.cs
následujícím kódem:
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");
}
// Select DepartmentID if TryUpdateModelAsync fails.
PopulateDepartmentsDropDownList(_context, emptyCourse.DepartmentID);
return Page();
}
}
}
Pokud chcete zobrazit komentáře ke kódu přeložené do jiných jazyků, než je angličtina, dejte nám vědět v této diskuzi na GitHubu.
Předchozí kód:
- Odvozuje z
DepartmentNamePageModel
. - Slouží
TryUpdateModelAsync
k zabránění nadměrnému umístění. - Odebere
ViewData["DepartmentID"]
.DepartmentNameSL
ze základní třídy je model silného typu a bude používán stránkou Razor . Modely silného typu jsou upřednostňované před slabě typovanými modely. Další informace naleznete v tématu Slabě typovaná data (ViewData a ViewBag).
Aktualizace stránky Vytvoření Razor kurzu
Aktualizujte Pages/Courses/Create.cshtml
následujícím kódem:
@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");}
}
Předchozí kód provede následující změny:
- Změní titulek z DepartmentID na Department.
"ViewBag.DepartmentID"
Nahradí zaDepartmentNameSL
(ze základní třídy).- Přidá možnost Vybrat oddělení. Tato změna v rozevíracím seznamu vykreslí možnost Vybrat oddělení, pokud ještě není vybráno žádné oddělení, a ne v prvním oddělení.
- Přidá ověřovací zprávu, když oddělení není vybrané.
Stránka Razor používá pomocníka pro výběr značek:
<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>
Otestujte stránku Vytvořit. Na stránce Vytvořit se místo ID oddělení zobrazí název oddělení.
Aktualizace modelu stránky Upravit kurz
Aktualizujte Pages/Courses/Edit.cshtml.cs
následujícím kódem:
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();
}
// Select current DepartmentID.
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");
}
// Select DepartmentID if TryUpdateModelAsync fails.
PopulateDepartmentsDropDownList(_context, courseToUpdate.DepartmentID);
return Page();
}
}
}
Změny se podobají změnám provedeným v modelu vytvořit stránku. V předchozím kódu PopulateDepartmentsDropDownList
předá ID oddělení, které toto oddělení vybere v rozevíracím seznamu.
Aktualizace stránky Upravit Razor kurz
Aktualizujte Pages/Courses/Edit.cshtml
následujícím kódem:
@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");}
}
Předchozí kód provede následující změny:
- Zobrazí ID kurzu. Obecně se nezobrazuje primární klíč (PK) entity. Sady PKS jsou obvykle pro uživatele nesmyslné. V tomto případě je PK číslo kurzu.
- Změní titulek rozevíracího seznamu Oddělení z ID oddělení na Oddělení.
"ViewBag.DepartmentID"
Nahradí zaDepartmentNameSL
(ze základní třídy).
Stránka obsahuje skryté pole (<input type="hidden">
) pro číslo kurzu. <label>
Přidání pomocné rutiny asp-for="Course.CourseID"
značek neodstraní potřebu skrytého pole. <input type="hidden">
je vyžadováno, aby číslo kurzu bylo zahrnuto do publikovaných dat, když uživatel klikne na Uložit.
Aktualizace podrobností kurzu a odstranění stránek
AsNoTracking může zvýšit výkon, pokud sledování není vyžadováno.
Aktualizace modelů stránek kurzu
Aktualizujte Pages/Courses/Delete.cshtml.cs
následujícím kódem, který chcete přidat 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");
}
}
}
Proveďte stejnou změnu v Pages/Courses/Details.cshtml.cs
souboru:
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();
}
}
}
Aktualizace stránek kurzu Razor
Aktualizujte Pages/Courses/Delete.cshtml
následujícím kódem:
@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>
Proveďte stejné změny na stránce Podrobnosti.
@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>
Testování stránek kurzu
Otestujte stránky pro vytvoření, úpravy, podrobnosti a odstranění.
Aktualizace stránek pro vytváření a úpravy instruktora
Instruktori mohou učit libovolný počet kurzů. Následující obrázek ukazuje stránku pro úpravy instruktora s polem zaškrtávacích políček kurzu.
Zaškrtávací políčka umožňují změny kurzů, ke kterým je instruktor přiřazený. Zaškrtávací políčko se zobrazí pro každý kurz v databázi. Jsou vybrány kurzy, ke kterým je instruktor přiřazený. Uživatel může zaškrtnutím nebo zrušením zaškrtnutí políček změnit zadání kurzu. Pokud byl počet kurzů mnohem větší, může lepší fungovat jiné uživatelské rozhraní. Metoda správy relace M:N se zde ale nezměnila. Pokud chcete vytvořit nebo odstranit relace, manipulujete s entitou spojení.
Vytvoření třídy pro přiřazená data kurzů
Vytvořte Models/SchoolViewModels/AssignedCourseData.cs
pomocí následujícího kódu:
namespace ContosoUniversity.Models.SchoolViewModels
{
public class AssignedCourseData
{
public int CourseID { get; set; }
public string Title { get; set; }
public bool Assigned { get; set; }
}
}
Třída AssignedCourseData
obsahuje data pro vytvoření zaškrtávacích políček pro kurzy přiřazené instruktorovi.
Vytvoření základní třídy modelu stránky instruktora
Pages/Instructors/InstructorCoursesPageModel.cs
Vytvořte základní třídu:
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);
}
}
}
}
}
}
Jedná se InstructorCoursesPageModel
o základní třídu, kterou použijete pro modely stránek Edit a Create. PopulateAssignedCourseData
přečte všechny Course
entity, které se mají naplnit AssignedCourseDataList
. Pro každý kurz kód nastaví CourseID
, titul a zda je instruktor přiřazen k kurzu. Sada hash se používá k efektivnímu vyhledávání.
Razor Vzhledem k tomu, že stránka neobsahuje kolekci entit kurzu, pořadač modelů nemůže automaticky aktualizovat CourseAssignments
navigační vlastnost. Místo použití pořadače modelu k aktualizaci CourseAssignments
navigační vlastnosti to uděláte v nové UpdateInstructorCourses
metodě. Proto je nutné vlastnost vyloučit CourseAssignments
z vazby modelu. To nevyžaduje žádnou změnu kódu, který volá TryUpdateModel
, protože používáte přetížení s deklarovanými vlastnostmi a CourseAssignments
není v seznamu zahrnutí.
Pokud nebyla vybrána žádná zaškrtávací políčka, kód inicializuje UpdateInstructorCourses
CourseAssignments
navigační vlastnost s prázdnou kolekcí a vrátí:
if (selectedCourses == null)
{
instructorToUpdate.CourseAssignments = new List<CourseAssignment>();
return;
}
Kód pak projde všemi kurzy v databázi a zkontroluje každý kurz proti kurzům, které jsou aktuálně přiřazené instruktorovi, a ty, které byly vybrány na stránce. Pro usnadnění efektivního vyhledávání jsou tyto dvě kolekce uloženy v HashSet
objektech.
Pokud bylo zaškrtnuté políčko pro kurz, ale kurz není v Instructor.CourseAssignments
navigační vlastnosti, kurz se přidá do kolekce v navigační vlastnosti.
if (selectedCoursesHS.Contains(course.CourseID.ToString()))
{
if (!instructorCourses.Contains(course.CourseID))
{
instructorToUpdate.CourseAssignments.Add(
new CourseAssignment
{
InstructorID = instructorToUpdate.ID,
CourseID = course.CourseID
});
}
}
Pokud není zaškrtnuté políčko pro kurz, ale kurz je v Instructor.CourseAssignments
navigační vlastnosti, kurz se z navigační vlastnosti odebere.
else
{
if (instructorCourses.Contains(course.CourseID))
{
CourseAssignment courseToRemove
= instructorToUpdate
.CourseAssignments
.SingleOrDefault(i => i.CourseID == course.CourseID);
context.Remove(courseToRemove);
}
}
Zpracování umístění kanceláře
Další relací, kterou musí stránka pro úpravy zpracovat, je relace 1:0 nebo 1, kterou má entita Instruktor s entitou OfficeAssignment
. Kód pro úpravy instruktora musí zpracovávat následující scénáře:
- Pokud uživatel vymaže přiřazení kanceláře, odstraňte entitu
OfficeAssignment
. - Pokud uživatel zadá přiřazení kanceláře a bude prázdný, vytvořte novou
OfficeAssignment
entitu. - Pokud uživatel změní přiřazení kanceláře, aktualizujte entitu
OfficeAssignment
.
Aktualizace modelu stránky Pro úpravy instruktora
Aktualizujte Pages/Instructors/Edit.cshtml.cs
následujícím kódem:
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();
}
}
}
Předchozí kód:
- Získá aktuální
Instructor
entitu z databáze pomocí dychtivého načítání proOfficeAssignment
vlastnosti ,CourseAssignment
aCourseAssignment.Course
navigace. - Aktualizuje načtenou
Instructor
entitu hodnotami z pořadače modelu.TryUpdateModel
zabraňuje nadměrnému umístění. - Pokud je umístění kanceláře prázdné, nastaví
Instructor.OfficeAssignment
se na hodnotu null. PokudInstructor.OfficeAssignment
je null, související řádek vOfficeAssignment
tabulce se odstraní. - Volání
PopulateAssignedCourseData
za účelem poskytnutí informací o zaškrtávacích polících pomocíAssignedCourseData
třídyOnGetAsync
modelu zobrazení OnPostAsync
VoláníUpdateInstructorCourses
, která použijí informace z zaškrtávacích políček na entitu instruktora, která se upravuje.- Volání
PopulateAssignedCourseData
aUpdateInstructorCourses
přihlášeníOnPostAsync
, pokudTryUpdateModel
selže. Tato metoda volá obnovení přiřazených dat kurzu zadaných na stránce při opětovném zobrazení s chybovou zprávou.
Aktualizace stránky Pro úpravy Razor instruktora
Aktualizujte Pages/Instructors/Edit.cshtml
následujícím kódem:
@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");}
}
Předchozí kód vytvoří tabulku HTML se třemi sloupci. Každý sloupec má zaškrtávací políčko a titulek obsahující číslo a název kurzu. Všechna zaškrtávací políčka mají stejný název ("selectedCourses"). Použití stejného názvu informuje pořadač modelu, aby s nimi zacházal jako se skupinou. Atribut hodnoty každého zaškrtávacího políčka je nastaven na CourseID
hodnotu . Když se stránka publikuje, pořadač modelu předá pole, které se skládá z CourseID
hodnot pouze pro zaškrtnutá políčka.
Po počátečním vykreslení zaškrtávacích políček se vyberou kurzy přiřazené instruktorovi.
Poznámka: Přístup k úpravě dat kurzu instruktora funguje dobře, když existuje omezený počet kurzů. U kolekcí, které jsou mnohem větší, by bylo vhodnější a efektivnější použít jiné uživatelské rozhraní a jinou metodu aktualizace.
Spusťte aplikaci a otestujte aktualizovanou stránku Pro úpravy instruktorů. Změňte některá zadání kurzu. Změny se projeví na stránce rejstříku.
Aktualizace stránky Pro vytvoření instruktora
Aktualizujte model stránky Razor a stránku pro vytvoření instruktora pomocí kódu podobného stránce Upravit:
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");}
}
Otestujte stránku pro vytvoření instruktora.
Aktualizace stránky Pro odstranění instruktora
Aktualizujte Pages/Instructors/Delete.cshtml.cs
následujícím kódem:
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");
}
}
}
Předchozí kód provede následující změny:
Používá dychtivé načítání pro
CourseAssignments
navigační vlastnost.CourseAssignments
musí být zahrnuté nebo se při odstranění instruktora neodstraní. Abyste se vyhnuli nutnosti je číst, nakonfigurujte kaskádové odstranění v databázi.Pokud je instruktor, který se má odstranit, přiřazený jako správce oddělení, odebere zadání instruktora z těchto oddělení.
Spusťte aplikaci a otestujte stránku Odstranit.
Další kroky
Tento kurz ukazuje aktualizaci souvisejících dat. Pokud narazíte na problémy, které nemůžete vyřešit, stáhněte nebo zobrazte dokončenou aplikaci. Pokyny ke stažení
Následující ilustrace znázorňují některé dokončené stránky.
Prozkoumejte a otestujte stránky kurzu Pro vytvoření a úpravy. Vytvořte nový kurz. Oddělení je vybráno primárním klíčem (celé číslo), nikoli jeho názvem. Upravte nový kurz. Po dokončení testování odstraňte nový kurz.
Vytvoření základní třídy pro sdílení společného kódu
Stránky Courses/Create and Courses/Edit potřebují seznam názvů oddělení. Pages/Courses/DepartmentNamePageModel.cshtml.cs
Vytvořte základní třídu pro stránky Create and Edit:
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);
}
}
}
Předchozí kód vytvoří seznam SelectList názvů oddělení. Je-li selectedDepartment
zadáno, je toto oddělení vybráno v sadě SelectList
.
Třídy modelu vytvoření a úpravy stránky budou odvozeny z DepartmentNamePageModel
.
Přizpůsobení stránek kurzů
Když se vytvoří nová entita kurzu, musí mít vztah k existujícímu oddělení. Pokud chcete přidat oddělení při vytváření kurzu, základní třída pro vytvoření a úpravy obsahuje rozevírací seznam pro výběr oddělení. Rozevírací seznam nastaví vlastnost cizího Course.DepartmentID
klíče (FK). EF CoreCourse.DepartmentID
používá jazyk FK k načtení Department
navigační vlastnosti.
Aktualizujte model vytvořit stránku následujícím kódem:
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");
}
// Select DepartmentID if TryUpdateModelAsync fails.
PopulateDepartmentsDropDownList(_context, emptyCourse.DepartmentID);
return Page();
}
}
}
Předchozí kód:
- Odvozuje z
DepartmentNamePageModel
. - Slouží
TryUpdateModelAsync
k zabránění nadměrnému umístění. ViewData["DepartmentID"]
Nahradí zaDepartmentNameSL
(ze základní třídy).
ViewData["DepartmentID"]
je nahrazen silným typem DepartmentNameSL
. Modely silného typu jsou upřednostňované před slabě typovanými modely. Další informace naleznete v tématu Slabě typovaná data (ViewData a ViewBag).
Aktualizace stránky Vytvoření kurzů
Aktualizujte Pages/Courses/Create.cshtml
následujícím kódem:
@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");}
}
Předchozí kód provede následující změny:
- Změní titulek z DepartmentID na Department.
"ViewBag.DepartmentID"
Nahradí zaDepartmentNameSL
(ze základní třídy).- Přidá možnost Vybrat oddělení. Tato změna místo prvního oddělení vykreslí možnost Vybrat oddělení.
- Přidá ověřovací zprávu, když oddělení není vybrané.
Stránka Razor používá pomocníka pro výběr značek:
<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>
Otestujte stránku Vytvořit. Na stránce Vytvořit se místo ID oddělení zobrazí název oddělení.
Aktualizujte stránku Úpravy kurzů.
Nahraďte kód v souboru Pages/Courses/Edit.cshtml.cs
následujícím kódem:
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();
}
// Select current DepartmentID.
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");
}
// Select DepartmentID if TryUpdateModelAsync fails.
PopulateDepartmentsDropDownList(_context, courseToUpdate.DepartmentID);
return Page();
}
}
}
Změny se podobají změnám provedeným v modelu vytvořit stránku. V předchozím kódu PopulateDepartmentsDropDownList
předá ID oddělení, které vybere oddělení zadané v rozevíracím seznamu.
Aktualizujte Pages/Courses/Edit.cshtml
následujícím kódem:
@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");}
}
Předchozí kód provede následující změny:
- Zobrazí ID kurzu. Obecně se nezobrazuje primární klíč (PK) entity. Sady PKS jsou obvykle pro uživatele nesmyslné. V tomto případě je PK číslo kurzu.
- Změní titulek z DepartmentID na Department.
"ViewBag.DepartmentID"
Nahradí zaDepartmentNameSL
(ze základní třídy).
Stránka obsahuje skryté pole (<input type="hidden">
) pro číslo kurzu. <label>
Přidání pomocné rutiny asp-for="Course.CourseID"
značek neodstraní potřebu skrytého pole. <input type="hidden">
je vyžadováno, aby číslo kurzu bylo zahrnuto do publikovaných dat, když uživatel klikne na Uložit.
Otestujte aktualizovaný kód. Vytvoření, úprava a odstranění kurzu
Přidání AsNoTrackingu do modelů podrobností a odstranění stránek
AsNoTracking může zvýšit výkon, pokud sledování není vyžadováno. Přidejte AsNoTracking
do modelu stránky Odstranit a Podrobnosti. Následující kód ukazuje aktualizovaný model stránky Odstranit:
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");
}
}
Aktualizujte metodu OnGetAsync
Pages/Courses/Details.cshtml.cs
v souboru:
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();
}
Úprava stránek Odstranit a Podrobnosti
Aktualizujte stránku Odstranit Razor následujícím kódem:
@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>
Proveďte stejné změny na stránce Podrobnosti.
Testování stránek kurzu
Otestujte vytváření, úpravy, podrobnosti a odstranění.
Aktualizace stránek instruktora
Následující části aktualizují stránky instruktora.
Přidání umístění kanceláře
Při úpravě záznamu instruktora můžete chtít aktualizovat zadání kanceláře instruktora. Entita Instructor
má relaci 1:0 nebo 1 s entitou OfficeAssignment
. Kód instruktora musí zpracovávat:
- Pokud uživatel vymaže přiřazení kanceláře, odstraňte entitu
OfficeAssignment
. - Pokud uživatel zadá přiřazení kanceláře a bude prázdný, vytvořte novou
OfficeAssignment
entitu. - Pokud uživatel změní přiřazení kanceláře, aktualizujte entitu
OfficeAssignment
.
Aktualizujte model stránek pro úpravy instruktorů následujícím kódem:
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");
}
}
Předchozí kód:
- Získá aktuální
Instructor
entitu z databáze pomocí dychtivého načítání proOfficeAssignment
navigační vlastnost. - Aktualizuje načtenou
Instructor
entitu hodnotami z pořadače modelu.TryUpdateModel
zabraňuje nadměrnému umístění. - Pokud je umístění kanceláře prázdné, nastaví
Instructor.OfficeAssignment
se na hodnotu null. PokudInstructor.OfficeAssignment
je null, související řádek vOfficeAssignment
tabulce se odstraní.
Aktualizace stránky pro úpravy instruktora
Aktualizujte Pages/Instructors/Edit.cshtml
umístěním kanceláře:
@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");}
}
Ověřte, že můžete změnit umístění kanceláře instruktora.
Přidání zadání kurzu na stránku Pro úpravy instruktora
Instruktori mohou učit libovolný počet kurzů. V této části přidáte možnost změnit zadání kurzu. Na následujícím obrázku je aktualizovaná stránka pro úpravy instruktora:
Course
a Instructor
má relaci M:N. Pokud chcete přidat a odebrat relace, přidáte a odeberete entity ze CourseAssignments
sady entit join.
zaškrtávací políčka umožňují změny kurzů, ke kterým je instruktor přiřazený. Zaškrtávací políčko se zobrazí pro každý kurz v databázi. Kurzy, ke kterým je instruktor přiřazen, jsou kontrolovány. Uživatel může zaškrtnutím nebo zrušením zaškrtnutí políček změnit zadání kurzu. Pokud počet kurzů byl mnohem větší:
- Pravděpodobně byste k zobrazení kurzů použili jiné uživatelské rozhraní.
- Metoda manipulace s entitou spojení pro vytvoření nebo odstranění relací by se nezměnila.
Přidání předmětů pro podporu stránek pro vytváření a úpravy instruktorů
Vytvořte Models/SchoolViewModels/AssignedCourseData.cs
pomocí následujícího kódu:
namespace ContosoUniversity.Models.SchoolViewModels
{
public class AssignedCourseData
{
public int CourseID { get; set; }
public string Title { get; set; }
public bool Assigned { get; set; }
}
}
Třída AssignedCourseData
obsahuje data pro vytvoření zaškrtávacích políček pro přiřazené kurzy instruktorem.
Pages/Instructors/InstructorCoursesPageModel.cshtml.cs
Vytvořte základní třídu:
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);
}
}
}
}
}
}
Jedná se InstructorCoursesPageModel
o základní třídu, kterou použijete pro modely stránek Edit a Create. PopulateAssignedCourseData
přečte všechny Course
entity, které se mají naplnit AssignedCourseDataList
. Pro každý kurz kód nastaví CourseID
, titul a zda je instruktor přiřazen k kurzu. Sada hash se používá k vytváření efektivních vyhledávání.
Instruktori – Upravit model stránky
Aktualizujte model stránky pro úpravy instruktora následujícím kódem:
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();
}
}
Předchozí kód zpracovává změny přiřazení office.
Aktualizujte zobrazení instruktora 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");}
}
Poznámka:
Když kód vložíte do sady Visual Studio, změní se konce řádků způsobem, který kód přeruší. Automatické formátování vrátíte jedním stisknutím kombinace kláves Ctrl+Z. Kombinace kláves Ctrl+Z opravuje konce řádků tak, aby vypadaly tak, jak vidíte tady. Odsazení nemusí být dokonalé, ale @:</tr><tr>
@:<td>
@:</td>
čáry , a @:</tr>
řádky musí být na jednom řádku, jak je znázorněno. Když vyberete blok nového kódu, stiskněte třikrát klávesu Tab, aby se nový kód zarovnál s existujícím kódem. Hlasujte nebo zkontrolujte stav této chyby pomocí tohoto odkazu.
Předchozí kód vytvoří tabulku HTML se třemi sloupci. Každý sloupec má zaškrtávací políčko a titulek obsahující číslo a název kurzu. Všechna zaškrtávací políčka mají stejný název ("selectedCourses"). Použití stejného názvu informuje pořadač modelu, aby s nimi zacházal jako se skupinou. Atribut hodnoty každého zaškrtávacího políčka je nastaven na CourseID
hodnotu . Když se stránka publikuje, pořadač modelu předá pole, které se skládá z CourseID
hodnot pouze pro zaškrtnutá políčka.
Po počátečním vykreslení zaškrtávacích políček jsou kurzy přiřazené instruktorovi zaškrtnuté atributy.
Spusťte aplikaci a otestujte aktualizovanou stránku pro úpravy instruktorů. Změňte některá zadání kurzu. Změny se projeví na stránce rejstříku.
Poznámka: Přístup k úpravě dat kurzu instruktora funguje dobře, když existuje omezený počet kurzů. U kolekcí, které jsou mnohem větší, by bylo vhodnější a efektivnější použít jiné uživatelské rozhraní a jinou metodu aktualizace.
Aktualizace stránky pro vytvoření instruktorů
Aktualizujte model stránky pro vytvoření instruktora následujícím kódem:
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();
}
}
}
Předchozí kód je podobný Pages/Instructors/Edit.cshtml.cs
kódu.
Aktualizujte stránku pro vytvoření Razor instruktora následujícím kódem:
@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");}
}
Otestujte stránku pro vytvoření instruktora.
Aktualizace stránky Odstranit
Aktualizujte model stránky Delete následujícím kódem:
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");
}
}
}
Předchozí kód provede následující změny:
Používá dychtivé načítání pro
CourseAssignments
navigační vlastnost.CourseAssignments
musí být zahrnuté nebo se při odstranění instruktora neodstraní. Abyste se vyhnuli nutnosti je číst, nakonfigurujte kaskádové odstranění v databázi.Pokud je instruktor, který se má odstranit, přiřazený jako správce oddělení, odebere zadání instruktora z těchto oddělení.