Bagian 7, Razor Halaman dengan EF Core inti ASP.NET - Perbarui Data Terkait
Oleh Tom Dykstra, Jon P Smith, dan Rick Anderson
Aplikasi web Contoso University menunjukkan cara membuat Razor aplikasi web Pages menggunakan EF Core dan Visual Studio. Untuk informasi tentang seri tutorial, lihat tutorial pertama.
Jika Anda mengalami masalah yang tidak dapat Anda selesaikan, unduh aplikasi yang telah selesai dan bandingkan kode tersebut dengan apa yang Anda buat dengan mengikuti tutorial.
Tutorial ini menunjukkan cara memperbarui data terkait. Ilustrasi berikut ini memperlihatkan beberapa halaman yang telah selesai.
Memperbarui halaman Buat dan Edit Kursus
Kode perancah untuk halaman Buat dan Edit Kursus memiliki daftar drop-down Departemen yang menunjukkan DepartmentID
, .int
Menu drop-down harus menampilkan nama Departemen, sehingga kedua halaman ini memerlukan daftar nama departemen. Untuk menyediakan daftar tersebut, gunakan kelas dasar untuk halaman Buat dan Edit.
Membuat kelas dasar untuk Membuat dan Mengedit Kursus
Buat Pages/Courses/DepartmentNamePageModel.cs
file dengan kode berikut:
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);
}
}
}
Kode sebelumnya membuat SelectList untuk berisi daftar nama departemen. Jika selectedDepartment
ditentukan, departemen tersebut dipilih di SelectList
.
Kelas Buat dan Edit model halaman akan berasal dari DepartmentNamePageModel
.
Memperbarui model halaman Buat Kursus
Kursus ditugaskan ke Departemen. Kelas dasar untuk halaman Buat dan Edit menyediakan SelectList
untuk memilih departemen. Daftar drop-down yang menggunakan SelectList
properti set Course.DepartmentID
kunci asing (FK). EF CoreCourse.DepartmentID
menggunakan FK untuk memuat Department
properti navigasi.
Perbarui Pages/Courses/Create.cshtml.cs
dengan kode berikut:
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();
}
}
}
Jika Anda ingin melihat komentar kode yang diterjemahkan ke bahasa selain bahasa Inggris, beri tahu kami dalam masalah diskusi GitHub ini.
Kode sebelumnya:
- Berasal dari
DepartmentNamePageModel
. - TryUpdateModelAsync Menggunakan untuk mencegah overposting.
ViewData["DepartmentID"]
Menghapus .DepartmentNameSL
SelectList
adalah model yang di ketik dengan kuat dan akan digunakan oleh Razor halaman. Model yang sangat di ketik lebih disukai daripada yang ditik lemah. Untuk informasi selengkapnya, lihat Data yang di ketik dengan lemah (ViewData dan ViewBag).
Memperbarui halaman Buat Razor Kursus
Perbarui Pages/Courses/Create.cshtml
dengan kode berikut:
@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");}
}
Kode sebelumnya membuat perubahan berikut:
- Mengubah keterangan dari DepartmentID ke Departemen.
"ViewBag.DepartmentID"
Mengganti denganDepartmentNameSL
(dari kelas dasar).- Menambahkan opsi "Pilih Departemen". Perubahan ini merender "Pilih Departemen" di menu drop-down ketika belum ada departemen yang dipilih, bukan departemen pertama.
- Menambahkan pesan validasi saat departemen tidak dipilih.
Halaman Razor menggunakan Pembantu Pilih Tag:
<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>
Uji halaman Buat. Halaman Buat menampilkan nama departemen daripada ID departemen.
Memperbarui model halaman Edit Kursus
Perbarui Pages/Courses/Edit.cshtml.cs
dengan kode berikut:
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();
}
}
}
Perubahannya mirip dengan yang dibuat dalam model halaman Buat. Dalam kode sebelumnya, PopulateDepartmentsDropDownList
meneruskan ID departemen, yang memilih departemen tersebut di daftar drop-down.
Memperbarui halaman Edit Razor Kursus
Perbarui Pages/Courses/Edit.cshtml
dengan kode berikut:
@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");}
}
Kode sebelumnya membuat perubahan berikut:
- Menampilkan ID kursus. Umumnya Kunci Primer (PK) entitas tidak ditampilkan. PK biasanya tidak berarti bagi pengguna. Dalam hal ini, PK adalah nomor kursus.
- Mengubah keterangan untuk drop-down Departemen dari DepartmentID ke Departemen.
"ViewBag.DepartmentID"
Mengganti denganDepartmentNameSL
, yang berada di kelas dasar.
Halaman berisi bidang tersembunyi (<input type="hidden">
) untuk nomor kursus. Menambahkan pembantu <label>
tag dengan asp-for="Course.CourseID"
tidak menghilangkan kebutuhan akan bidang tersembunyi. <input type="hidden">
diperlukan agar nomor kursus disertakan dalam data yang diposting saat pengguna memilih Simpan.
Memperbarui model halaman Kursus
AsNoTracking dapat meningkatkan performa saat pelacakan tidak diperlukan.
Perbarui Pages/Courses/Delete.cshtml.cs
dan Pages/Courses/Details.cshtml.cs
dengan menambahkan AsNoTracking
ke OnGetAsync
metode:
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();
}
Memperbarui halaman Kursus Razor
Perbarui Pages/Courses/Delete.cshtml
dengan kode berikut:
@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>
Buat perubahan yang sama pada halaman Detail.
@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>
Menguji halaman Kursus
Uji halaman buat, edit, detail, dan hapus.
Memperbarui halaman Buat dan Edit instruktur
Instruktur dapat mengajarkan sejumlah kursus. Gambar berikut menunjukkan halaman Edit instruktur dengan array kotak centang kursus.
Kotak centang mengaktifkan perubahan pada kursus tempat instruktur ditetapkan. Kotak centang ditampilkan untuk setiap kursus dalam database. Kursus yang ditetapkan instruktur dipilih. Pengguna dapat memilih atau menghapus kotak centang untuk mengubah penetapan kursus. Jika jumlah kursus jauh lebih besar, UI yang berbeda mungkin bekerja lebih baik. Tetapi metode mengelola hubungan banyak ke banyak yang ditunjukkan di sini tidak akan berubah. Untuk membuat atau menghapus hubungan, Anda memanipulasi entitas gabungan.
Membuat kelas untuk data kursus yang ditetapkan
Buat Models/SchoolViewModels/AssignedCourseData.cs
dengan kode berikut:
namespace ContosoUniversity.Models.SchoolViewModels
{
public class AssignedCourseData
{
public int CourseID { get; set; }
public string Title { get; set; }
public bool Assigned { get; set; }
}
}
Kelas AssignedCourseData
berisi data untuk membuat kotak centang untuk kursus yang ditetapkan ke instruktur.
Membuat kelas dasar model halaman Instruktur
Pages/Instructors/InstructorCoursesPageModel.cs
Buat kelas dasar:
using ContosoUniversity.Data;
using ContosoUniversity.Models;
using ContosoUniversity.Models.SchoolViewModels;
using Microsoft.AspNetCore.Mvc.RazorPages;
using System.Collections.Generic;
using System.Linq;
namespace ContosoUniversity.Pages.Instructors
{
public class InstructorCoursesPageModel : PageModel
{
public List<AssignedCourseData> AssignedCourseDataList;
public void PopulateAssignedCourseData(SchoolContext context,
Instructor instructor)
{
var allCourses = context.Courses;
var instructorCourses = new HashSet<int>(
instructor.Courses.Select(c => c.CourseID));
AssignedCourseDataList = new List<AssignedCourseData>();
foreach (var course in allCourses)
{
AssignedCourseDataList.Add(new AssignedCourseData
{
CourseID = course.CourseID,
Title = course.Title,
Assigned = instructorCourses.Contains(course.CourseID)
});
}
}
}
}
InstructorCoursesPageModel
adalah kelas dasar untuk model halaman Edit dan Buat. PopulateAssignedCourseData
membaca semua Course
entitas untuk mengisi AssignedCourseDataList
. Untuk setiap kursus, kode menetapkan CourseID
, judul, dan apakah instruktur ditetapkan ke kursus atau tidak. HashSet digunakan untuk pencarian yang efisien.
Menangani lokasi kantor
Hubungan lain yang harus ditangani halaman edit adalah hubungan satu-ke-nol-atau-satu yang dimiliki entitas Instruktur dengan OfficeAssignment
entitas. Kode edit instruktur harus menangani skenario berikut:
- Jika pengguna menghapus penetapan kantor, hapus
OfficeAssignment
entitas. - Jika pengguna memasukkan penetapan kantor dan kosong, buat entitas baru
OfficeAssignment
. - Jika pengguna mengubah penetapan office, perbarui
OfficeAssignment
entitas.
Memperbarui model halaman Edit Instruktur
Perbarui Pages/Instructors/Edit.cshtml.cs
dengan kode berikut:
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);
}
}
}
}
}
}
Kode sebelumnya:
- Mendapatkan entitas saat ini
Instructor
dari database menggunakan pemuatan bersemangatOfficeAssignment
untuk properti navigasi danCourses
. - Memperbarui entitas yang diambil
Instructor
dengan nilai dari pengikat model. TryUpdateModelAsyncmencegah overposting. - Jika lokasi kantor kosong, atur
Instructor.OfficeAssignment
ke null. KetikaInstructor.OfficeAssignment
null, baris terkait dalamOfficeAssignment
tabel dihapus. PopulateAssignedCourseData
Panggilan masukOnGetAsync
untuk memberikan informasi untuk kotak centang menggunakanAssignedCourseData
kelas model tampilan.UpdateInstructorCourses
Panggilan masuk untuk menerapkan informasi dari kotak centang ke entitas Instruktur yang sedang dieditOnPostAsync
.PopulateAssignedCourseData
Panggilan danUpdateInstructorCourses
masukOnPostAsync
jika TryUpdateModelAsync gagal. Metode ini memanggil pemulihan data kursus yang ditetapkan yang dimasukkan di halaman ketika diputar ulang dengan pesan kesalahan.
Razor Karena halaman tidak memiliki kumpulan entitas Kursus, pengikat model tidak dapat memperbarui Courses
properti navigasi secara otomatis. Alih-alih menggunakan pengikat model untuk memperbarui Courses
properti navigasi, itu dilakukan dalam metode baru UpdateInstructorCourses
. Oleh karena itu Anda perlu mengecualikan Courses
properti dari pengikatan model. Ini tidak memerlukan perubahan apa pun pada kode yang memanggil TryUpdateModelAsync karena Anda menggunakan kelebihan beban dengan properti yang dideklarasikan dan Courses
tidak ada dalam daftar sertakan.
Jika tidak ada kotak centang yang dipilih, kode dalam UpdateInstructorCourses
menginisialisasi instructorToUpdate.Courses
dengan koleksi kosong dan mengembalikan:
if (selectedCourses == null)
{
instructorToUpdate.Courses = new List<Course>();
return;
}
Kode kemudian mengulangi semua kursus dalam database dan memeriksa setiap kursus terhadap yang saat ini ditetapkan ke instruktur versus yang dipilih di halaman. Untuk memfasilitasi pencarian yang efisien, dua koleksi terakhir disimpan dalam HashSet
objek.
Jika kotak centang untuk kursus dipilih tetapi kursus tidak ada di Instructor.Courses
properti navigasi, kursus ditambahkan ke koleksi di properti navigasi.
if (selectedCoursesHS.Contains(course.CourseID.ToString()))
{
if (!instructorCourses.Contains(course.CourseID))
{
instructorToUpdate.Courses.Add(course);
}
}
Jika kotak centang untuk kursus tidak dipilih, tetapi kursus berada di Instructor.Courses
properti navigasi, kursus akan dihapus dari properti navigasi.
else
{
if (instructorCourses.Contains(course.CourseID))
{
var courseToRemove = instructorToUpdate.Courses.Single(
c => c.CourseID == course.CourseID);
instructorToUpdate.Courses.Remove(courseToRemove);
}
}
Memperbarui halaman Edit Razor Instruktur
Perbarui Pages/Instructors/Edit.cshtml
dengan kode berikut:
@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");}
}
Kode sebelumnya membuat tabel HTML yang memiliki tiga kolom. Setiap kolom memiliki kotak centang dan keterangan yang berisi nomor kursus dan judul. Semua kotak centang memiliki nama yang sama ("selectedCourses"). Menggunakan nama yang sama menginformasikan pengikat model untuk memperlakukannya sebagai grup. Atribut nilai dari setiap kotak centang diatur ke CourseID
. Saat halaman diposting, pengikat model meneruskan array yang terdiri dari CourseID
nilai hanya untuk kotak centang yang dipilih.
Ketika kotak centang awalnya dirender, kursus yang ditetapkan ke instruktur dipilih.
Catatan: Pendekatan yang diambil di sini untuk mengedit data kursus instruktur berfungsi dengan baik ketika ada sejumlah kursus yang terbatas. Untuk koleksi yang jauh lebih besar, UI yang berbeda dan metode pembaruan yang berbeda akan lebih dapat digunakan dan efisien.
Jalankan aplikasi dan uji halaman Edit Instruktur yang diperbarui. Ubah beberapa tugas kursus. Perubahan tercermin pada halaman Indeks.
Memperbarui halaman Buat Instruktur
Perbarui model halaman Buat Instruktur dan dengan kode yang mirip dengan halaman Edit:
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();
}
}
}
Kode sebelumnya:
Menambahkan pengelogan untuk pesan peringatan dan kesalahan.
LoadPanggilan , yang mengambil semua Kursus dalam satu panggilan database. Untuk koleksi kecil, ini adalah pengoptimalan saat menggunakan FindAsync.
FindAsync
mengembalikan entitas terlacak tanpa permintaan ke database.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)
membuat hubungan baruInstructor
menggunakan banyak-ke-banyak tanpa secara eksplisit memetakan tabel gabungan. Banyak ke banyak ditambahkan di EF 5.0.
Uji halaman Buat instruktur.
Perbarui halaman Buat Razor Instruktur dengan kode yang mirip dengan halaman Edit:
@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");}
}
Memperbarui halaman Hapus Instruktur
Perbarui Pages/Instructors/Delete.cshtml.cs
dengan kode berikut:
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");
}
}
}
Kode sebelumnya membuat perubahan berikut:
Menggunakan pemuatan bersemangat untuk
Courses
properti navigasi.Courses
harus disertakan atau tidak dihapus saat instruktur dihapus. Untuk menghindari perlu membacanya, konfigurasikan penghapusan kaskade dalam database.Jika instruktur yang akan dihapus ditetapkan sebagai administrator departemen mana pun, menghapus penugasan instruktur dari departemen tersebut.
Jalankan aplikasi dan uji halaman Hapus.
Langkah berikutnya
Tutorial ini menunjukkan cara memperbarui data terkait. Ilustrasi berikut ini memperlihatkan beberapa halaman yang telah selesai.
Memperbarui halaman Buat dan Edit Kursus
Kode perancah untuk halaman Buat dan Edit Kursus memiliki daftar drop-down Departemen yang memperlihatkan ID Departemen (bilangan bulat). Menu drop-down harus menampilkan nama Departemen, sehingga kedua halaman ini memerlukan daftar nama departemen. Untuk menyediakan daftar tersebut, gunakan kelas dasar untuk halaman Buat dan Edit.
Membuat kelas dasar untuk Membuat dan Mengedit Kursus
Buat Pages/Courses/DepartmentNamePageModel.cs
file dengan kode berikut:
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);
}
}
}
Kode sebelumnya membuat SelectList untuk berisi daftar nama departemen. Jika selectedDepartment
ditentukan, departemen tersebut dipilih di SelectList
.
Kelas Buat dan Edit model halaman akan berasal dari DepartmentNamePageModel
.
Memperbarui model halaman Buat Kursus
Kursus ditugaskan ke Departemen. Kelas dasar untuk halaman Buat dan Edit menyediakan SelectList
untuk memilih departemen. Daftar drop-down yang menggunakan SelectList
properti set Course.DepartmentID
kunci asing (FK). EF CoreCourse.DepartmentID
menggunakan FK untuk memuat Department
properti navigasi.
Perbarui Pages/Courses/Create.cshtml.cs
dengan kode berikut:
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();
}
}
}
Jika Anda ingin melihat komentar kode yang diterjemahkan ke bahasa selain bahasa Inggris, beri tahu kami dalam masalah diskusi GitHub ini.
Kode sebelumnya:
- Berasal dari
DepartmentNamePageModel
. TryUpdateModelAsync
Menggunakan untuk mencegah overposting.ViewData["DepartmentID"]
Menghapus .DepartmentNameSL
dari kelas dasar adalah model yang ditik dengan kuat dan akan digunakan oleh Razor halaman. Model yang sangat di ketik lebih disukai daripada yang ditik lemah. Untuk informasi selengkapnya, lihat Data yang di ketik dengan lemah (ViewData dan ViewBag).
Memperbarui halaman Buat Razor Kursus
Perbarui Pages/Courses/Create.cshtml
dengan kode berikut:
@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");}
}
Kode sebelumnya membuat perubahan berikut:
- Mengubah keterangan dari DepartmentID ke Departemen.
"ViewBag.DepartmentID"
Mengganti denganDepartmentNameSL
(dari kelas dasar).- Menambahkan opsi "Pilih Departemen". Perubahan ini merender "Pilih Departemen" di menu drop-down ketika belum ada departemen yang dipilih, bukan departemen pertama.
- Menambahkan pesan validasi saat departemen tidak dipilih.
Halaman Razor menggunakan Pembantu Pilih Tag:
<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>
Uji halaman Buat. Halaman Buat menampilkan nama departemen daripada ID departemen.
Memperbarui model halaman Edit Kursus
Perbarui Pages/Courses/Edit.cshtml.cs
dengan kode berikut:
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();
}
}
}
Perubahannya mirip dengan yang dibuat dalam model halaman Buat. Dalam kode sebelumnya, PopulateDepartmentsDropDownList
meneruskan ID departemen, yang memilih departemen tersebut di daftar drop-down.
Memperbarui halaman Edit Razor Kursus
Perbarui Pages/Courses/Edit.cshtml
dengan kode berikut:
@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");}
}
Kode sebelumnya membuat perubahan berikut:
- Menampilkan ID kursus. Umumnya Kunci Primer (PK) entitas tidak ditampilkan. PK biasanya tidak berarti bagi pengguna. Dalam hal ini, PK adalah nomor kursus.
- Mengubah keterangan untuk drop-down Departemen dari DepartmentID ke Departemen.
"ViewBag.DepartmentID"
Mengganti denganDepartmentNameSL
(dari kelas dasar).
Halaman berisi bidang tersembunyi (<input type="hidden">
) untuk nomor kursus. Menambahkan pembantu <label>
tag dengan asp-for="Course.CourseID"
tidak menghilangkan kebutuhan akan bidang tersembunyi. <input type="hidden">
diperlukan agar nomor kursus disertakan dalam data yang diposting saat pengguna mengklik Simpan.
Memperbarui halaman Detail Kursus dan Hapus
AsNoTracking dapat meningkatkan performa saat pelacakan tidak diperlukan.
Memperbarui model halaman Kursus
Perbarui Pages/Courses/Delete.cshtml.cs
dengan kode berikut untuk menambahkan 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");
}
}
}
Buat perubahan yang sama dalam Pages/Courses/Details.cshtml.cs
file:
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();
}
}
}
Memperbarui halaman Kursus Razor
Perbarui Pages/Courses/Delete.cshtml
dengan kode berikut:
@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>
Buat perubahan yang sama pada halaman Detail.
@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>
Menguji halaman Kursus
Uji halaman buat, edit, detail, dan hapus.
Memperbarui halaman Buat dan Edit instruktur
Instruktur dapat mengajarkan sejumlah kursus. Gambar berikut menunjukkan halaman Edit instruktur dengan array kotak centang kursus.
Kotak centang mengaktifkan perubahan pada kursus tempat instruktur ditetapkan. Kotak centang ditampilkan untuk setiap kursus dalam database. Kursus yang ditetapkan instruktur dipilih. Pengguna dapat memilih atau menghapus kotak centang untuk mengubah penetapan kursus. Jika jumlah kursus jauh lebih besar, UI yang berbeda mungkin bekerja lebih baik. Tetapi metode mengelola hubungan banyak ke banyak yang ditunjukkan di sini tidak akan berubah. Untuk membuat atau menghapus hubungan, Anda memanipulasi entitas gabungan.
Membuat kelas untuk data kursus yang ditetapkan
Buat Models/SchoolViewModels/AssignedCourseData.cs
dengan kode berikut:
namespace ContosoUniversity.Models.SchoolViewModels
{
public class AssignedCourseData
{
public int CourseID { get; set; }
public string Title { get; set; }
public bool Assigned { get; set; }
}
}
Kelas AssignedCourseData
berisi data untuk membuat kotak centang untuk kursus yang ditetapkan ke instruktur.
Membuat kelas dasar model halaman Instruktur
Pages/Instructors/InstructorCoursesPageModel.cs
Buat kelas dasar:
using ContosoUniversity.Data;
using ContosoUniversity.Models;
using ContosoUniversity.Models.SchoolViewModels;
using Microsoft.AspNetCore.Mvc.RazorPages;
using System.Collections.Generic;
using System.Linq;
namespace ContosoUniversity.Pages.Instructors
{
public class InstructorCoursesPageModel : PageModel
{
public List<AssignedCourseData> AssignedCourseDataList;
public void PopulateAssignedCourseData(SchoolContext context,
Instructor instructor)
{
var allCourses = context.Courses;
var instructorCourses = new HashSet<int>(
instructor.CourseAssignments.Select(c => c.CourseID));
AssignedCourseDataList = new List<AssignedCourseData>();
foreach (var course in allCourses)
{
AssignedCourseDataList.Add(new AssignedCourseData
{
CourseID = course.CourseID,
Title = course.Title,
Assigned = instructorCourses.Contains(course.CourseID)
});
}
}
public void UpdateInstructorCourses(SchoolContext context,
string[] selectedCourses, Instructor instructorToUpdate)
{
if (selectedCourses == null)
{
instructorToUpdate.CourseAssignments = new List<CourseAssignment>();
return;
}
var selectedCoursesHS = new HashSet<string>(selectedCourses);
var instructorCourses = new HashSet<int>
(instructorToUpdate.CourseAssignments.Select(c => c.Course.CourseID));
foreach (var course in context.Courses)
{
if (selectedCoursesHS.Contains(course.CourseID.ToString()))
{
if (!instructorCourses.Contains(course.CourseID))
{
instructorToUpdate.CourseAssignments.Add(
new CourseAssignment
{
InstructorID = instructorToUpdate.ID,
CourseID = course.CourseID
});
}
}
else
{
if (instructorCourses.Contains(course.CourseID))
{
CourseAssignment courseToRemove
= instructorToUpdate
.CourseAssignments
.SingleOrDefault(i => i.CourseID == course.CourseID);
context.Remove(courseToRemove);
}
}
}
}
}
}
InstructorCoursesPageModel
adalah kelas dasar yang akan Anda gunakan untuk model halaman Edit dan Buat. PopulateAssignedCourseData
membaca semua Course
entitas untuk mengisi AssignedCourseDataList
. Untuk setiap kursus, kode menetapkan CourseID
, judul, dan apakah instruktur ditetapkan ke kursus atau tidak. HashSet digunakan untuk pencarian yang efisien.
Razor Karena halaman tidak memiliki kumpulan entitas Kursus, pengikat model tidak dapat memperbarui CourseAssignments
properti navigasi secara otomatis. Alih-alih menggunakan pengikat model untuk memperbarui CourseAssignments
properti navigasi, Anda melakukannya dalam metode baru UpdateInstructorCourses
. Oleh karena itu Anda perlu mengecualikan CourseAssignments
properti dari pengikatan model. Ini tidak memerlukan perubahan apa pun pada kode yang memanggil TryUpdateModel
karena Anda menggunakan kelebihan beban dengan properti yang dideklarasikan dan CourseAssignments
tidak ada dalam daftar sertakan.
Jika tidak ada kotak centang yang dipilih, kode dalam UpdateInstructorCourses
menginisialisasi CourseAssignments
properti navigasi dengan koleksi kosong dan mengembalikan:
if (selectedCourses == null)
{
instructorToUpdate.CourseAssignments = new List<CourseAssignment>();
return;
}
Kode kemudian mengulangi semua kursus dalam database dan memeriksa setiap kursus terhadap yang saat ini ditetapkan ke instruktur versus yang dipilih di halaman. Untuk memfasilitasi pencarian yang efisien, dua koleksi terakhir disimpan dalam HashSet
objek.
Jika kotak centang untuk kursus dipilih tetapi kursus tidak ada di Instructor.CourseAssignments
properti navigasi, kursus ditambahkan ke koleksi di properti navigasi.
if (selectedCoursesHS.Contains(course.CourseID.ToString()))
{
if (!instructorCourses.Contains(course.CourseID))
{
instructorToUpdate.CourseAssignments.Add(
new CourseAssignment
{
InstructorID = instructorToUpdate.ID,
CourseID = course.CourseID
});
}
}
Jika kotak centang untuk kursus tidak dipilih, tetapi kursus berada di Instructor.CourseAssignments
properti navigasi, kursus akan dihapus dari properti navigasi.
else
{
if (instructorCourses.Contains(course.CourseID))
{
CourseAssignment courseToRemove
= instructorToUpdate
.CourseAssignments
.SingleOrDefault(i => i.CourseID == course.CourseID);
context.Remove(courseToRemove);
}
}
Menangani lokasi kantor
Hubungan lain yang harus ditangani halaman edit adalah hubungan satu-ke-nol-atau-satu yang dimiliki entitas Instruktur dengan OfficeAssignment
entitas. Kode edit instruktur harus menangani skenario berikut:
- Jika pengguna menghapus penetapan kantor, hapus
OfficeAssignment
entitas. - Jika pengguna memasukkan penetapan kantor dan kosong, buat entitas baru
OfficeAssignment
. - Jika pengguna mengubah penetapan office, perbarui
OfficeAssignment
entitas.
Memperbarui model halaman Edit Instruktur
Perbarui Pages/Instructors/Edit.cshtml.cs
dengan kode berikut:
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();
}
}
}
Kode sebelumnya:
- Mendapatkan entitas saat ini
Instructor
dari database menggunakan pemuatan bersemangat untukOfficeAssignment
properti navigasi , ,CourseAssignment
danCourseAssignment.Course
. - Memperbarui entitas yang diambil
Instructor
dengan nilai dari pengikat model.TryUpdateModel
mencegah overposting. - Jika lokasi kantor kosong, atur
Instructor.OfficeAssignment
ke null. KetikaInstructor.OfficeAssignment
null, baris terkait dalamOfficeAssignment
tabel dihapus. PopulateAssignedCourseData
Panggilan masukOnGetAsync
untuk memberikan informasi untuk kotak centang menggunakanAssignedCourseData
kelas model tampilan.UpdateInstructorCourses
Panggilan masuk untuk menerapkan informasi dari kotak centang ke entitas Instruktur yang sedang dieditOnPostAsync
.PopulateAssignedCourseData
Panggilan danUpdateInstructorCourses
masukOnPostAsync
jikaTryUpdateModel
gagal. Metode ini memanggil pemulihan data kursus yang ditetapkan yang dimasukkan di halaman ketika diputar ulang dengan pesan kesalahan.
Memperbarui halaman Edit Razor Instruktur
Perbarui Pages/Instructors/Edit.cshtml
dengan kode berikut:
@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");}
}
Kode sebelumnya membuat tabel HTML yang memiliki tiga kolom. Setiap kolom memiliki kotak centang dan keterangan yang berisi nomor kursus dan judul. Semua kotak centang memiliki nama yang sama ("selectedCourses"). Menggunakan nama yang sama menginformasikan pengikat model untuk memperlakukannya sebagai grup. Atribut nilai dari setiap kotak centang diatur ke CourseID
. Saat halaman diposting, pengikat model meneruskan array yang terdiri dari CourseID
nilai hanya untuk kotak centang yang dipilih.
Ketika kotak centang awalnya dirender, kursus yang ditetapkan ke instruktur dipilih.
Catatan: Pendekatan yang diambil di sini untuk mengedit data kursus instruktur berfungsi dengan baik ketika ada sejumlah kursus yang terbatas. Untuk koleksi yang jauh lebih besar, UI yang berbeda dan metode pembaruan yang berbeda akan lebih dapat digunakan dan efisien.
Jalankan aplikasi dan uji halaman Edit Instruktur yang diperbarui. Ubah beberapa tugas kursus. Perubahan tercermin pada halaman Indeks.
Memperbarui halaman Buat Instruktur
Perbarui model dan Razor halaman halaman Buat Instruktur dengan kode yang mirip dengan halaman Edit:
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");}
}
Uji halaman Buat instruktur.
Memperbarui halaman Hapus Instruktur
Perbarui Pages/Instructors/Delete.cshtml.cs
dengan kode berikut:
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");
}
}
}
Kode sebelumnya membuat perubahan berikut:
Menggunakan pemuatan bersemangat untuk
CourseAssignments
properti navigasi.CourseAssignments
harus disertakan atau tidak dihapus saat instruktur dihapus. Untuk menghindari perlu membacanya, konfigurasikan penghapusan kaskade dalam database.Jika instruktur yang akan dihapus ditetapkan sebagai administrator departemen mana pun, menghapus penugasan instruktur dari departemen tersebut.
Jalankan aplikasi dan uji halaman Hapus.
Langkah berikutnya
Tutorial ini menunjukkan pembaruan data terkait. Jika Mengalami masalah, Anda tidak dapat menyelesaikan, mengunduh, atau melihat aplikasi yang telah selesai. Unduh instruksi.
Ilustrasi berikut ini memperlihatkan beberapa halaman yang telah selesai.
Periksa dan uji halaman kursus Buat dan Edit. Buat kursus baru. Departemen dipilih oleh kunci utamanya (bilangan bulat), bukan namanya. Edit kursus baru. Setelah Anda selesai menguji, hapus kursus baru.
Membuat kelas dasar untuk berbagi kode umum
Halaman Kursus/Buat dan Kursus/Edit masing-masing memerlukan daftar nama departemen. Pages/Courses/DepartmentNamePageModel.cshtml.cs
Buat kelas dasar untuk halaman Buat dan 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);
}
}
}
Kode sebelumnya membuat SelectList untuk berisi daftar nama departemen. Jika selectedDepartment
ditentukan, departemen tersebut dipilih di SelectList
.
Kelas Buat dan Edit model halaman akan berasal dari DepartmentNamePageModel
.
Mengkustomisasi Halaman Kursus
Ketika entitas kursus baru dibuat, entitas tersebut harus memiliki hubungan dengan departemen yang ada. Untuk menambahkan departemen saat membuat kursus, kelas dasar untuk Buat dan Edit berisi daftar drop-down untuk memilih departemen. Daftar drop-down mengatur Course.DepartmentID
properti kunci asing (FK). EF CoreCourse.DepartmentID
menggunakan FK untuk memuat Department
properti navigasi.
Perbarui model halaman Buat dengan kode berikut:
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();
}
}
}
Kode sebelumnya:
- Berasal dari
DepartmentNamePageModel
. TryUpdateModelAsync
Menggunakan untuk mencegah overposting.ViewData["DepartmentID"]
Mengganti denganDepartmentNameSL
(dari kelas dasar).
ViewData["DepartmentID"]
diganti dengan jenis yang kuat DepartmentNameSL
. Model yang sangat di ketik lebih disukai daripada yang ditik lemah. Untuk informasi selengkapnya, lihat Data yang di ketik dengan lemah (ViewData dan ViewBag).
Perbarui halaman Buat Kursus
Perbarui Pages/Courses/Create.cshtml
dengan kode berikut:
@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");}
}
Markup sebelumnya membuat perubahan berikut:
- Mengubah keterangan dari DepartmentID ke Departemen.
"ViewBag.DepartmentID"
Mengganti denganDepartmentNameSL
(dari kelas dasar).- Menambahkan opsi "Pilih Departemen". Perubahan ini merender "Pilih Departemen" daripada departemen pertama.
- Menambahkan pesan validasi saat departemen tidak dipilih.
Halaman Razor menggunakan Pembantu Pilih Tag:
<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>
Uji halaman Buat. Halaman Buat menampilkan nama departemen daripada ID departemen.
Perbarui halaman Edit Kursus.
Ganti kode di Pages/Courses/Edit.cshtml.cs
dengan kode berikut:
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();
}
}
}
Perubahannya mirip dengan yang dibuat dalam model halaman Buat. Dalam kode sebelumnya, PopulateDepartmentsDropDownList
meneruskan ID departemen, yang memilih departemen yang ditentukan dalam daftar drop-down.
Perbarui Pages/Courses/Edit.cshtml
dengan markup berikut:
@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");}
}
Markup sebelumnya membuat perubahan berikut:
- Menampilkan ID kursus. Umumnya Kunci Primer (PK) entitas tidak ditampilkan. PK biasanya tidak berarti bagi pengguna. Dalam hal ini, PK adalah nomor kursus.
- Mengubah keterangan dari DepartmentID ke Departemen.
"ViewBag.DepartmentID"
Mengganti denganDepartmentNameSL
(dari kelas dasar).
Halaman berisi bidang tersembunyi (<input type="hidden">
) untuk nomor kursus. Menambahkan pembantu <label>
tag dengan asp-for="Course.CourseID"
tidak menghilangkan kebutuhan akan bidang tersembunyi. <input type="hidden">
diperlukan agar nomor kursus disertakan dalam data yang diposting saat pengguna mengklik Simpan.
Uji kode yang diperbarui. Membuat, mengedit, dan menghapus kursus.
Menambahkan AsNoTracking ke model halaman Detail dan Hapus
AsNoTracking dapat meningkatkan performa saat pelacakan tidak diperlukan. Tambahkan AsNoTracking
ke model halaman Hapus dan Detail. Kode berikut menunjukkan model halaman Hapus yang diperbarui:
public class DeleteModel : PageModel
{
private readonly ContosoUniversity.Data.SchoolContext _context;
public DeleteModel(ContosoUniversity.Data.SchoolContext context)
{
_context = context;
}
[BindProperty]
public Course Course { get; set; }
public async Task<IActionResult> OnGetAsync(int? id)
{
if (id == null)
{
return NotFound();
}
Course = await _context.Courses
.AsNoTracking()
.Include(c => c.Department)
.FirstOrDefaultAsync(m => m.CourseID == id);
if (Course == null)
{
return NotFound();
}
return Page();
}
public async Task<IActionResult> OnPostAsync(int? id)
{
if (id == null)
{
return NotFound();
}
Course = await _context.Courses
.AsNoTracking()
.FirstOrDefaultAsync(m => m.CourseID == id);
if (Course != null)
{
_context.Courses.Remove(Course);
await _context.SaveChangesAsync();
}
return RedirectToPage("./Index");
}
}
OnGetAsync
Perbarui metode dalam Pages/Courses/Details.cshtml.cs
file:
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();
}
Mengubah halaman Hapus dan Detail
Perbarui halaman Hapus Razor dengan markup berikut:
@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>
Buat perubahan yang sama pada halaman Detail.
Menguji halaman Kursus
Uji buat, edit, detail, dan hapus.
Memperbarui halaman instruktur
Bagian berikut memperbarui halaman instruktur.
Menambahkan lokasi kantor
Saat mengedit catatan instruktur, Anda mungkin ingin memperbarui penetapan kantor instruktur. Entitas Instructor
memiliki hubungan satu-ke-nol-atau-satu dengan OfficeAssignment
entitas. Kode instruktur harus menangani:
- Jika pengguna menghapus penetapan kantor, hapus
OfficeAssignment
entitas. - Jika pengguna memasukkan penetapan kantor dan kosong, buat entitas baru
OfficeAssignment
. - Jika pengguna mengubah penetapan office, perbarui
OfficeAssignment
entitas.
Perbarui model halaman Edit instruktur dengan kode berikut:
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");
}
}
Kode sebelumnya:
- Mendapatkan entitas saat ini
Instructor
dari database menggunakan pemuatan bersemangat untukOfficeAssignment
properti navigasi. - Memperbarui entitas yang diambil
Instructor
dengan nilai dari pengikat model.TryUpdateModel
mencegah overposting. - Jika lokasi kantor kosong, atur
Instructor.OfficeAssignment
ke null. KetikaInstructor.OfficeAssignment
null, baris terkait dalamOfficeAssignment
tabel dihapus.
Memperbarui halaman Edit instruktur
Perbarui Pages/Instructors/Edit.cshtml
dengan lokasi kantor:
@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");}
}
Verifikasi bahwa Anda dapat mengubah lokasi kantor instruktur.
Menambahkan tugas Kursus ke halaman Edit instruktur
Instruktur dapat mengajarkan sejumlah kursus. Di bagian ini, Anda menambahkan kemampuan untuk mengubah tugas kursus. Gambar berikut menunjukkan halaman Edit instruktur yang diperbarui:
Course
dan Instructor
memiliki hubungan banyak ke banyak. Untuk menambahkan dan menghapus hubungan, Anda menambahkan dan menghapus entitas dari CourseAssignments
kumpulan entitas gabungan.
kotak centang mengaktifkan perubahan pada kursus yang ditetapkan instruktur. Kotak centang ditampilkan untuk setiap kursus dalam database. Kursus yang ditetapkan instruktur diperiksa. Pengguna dapat memilih atau menghapus kotak centang untuk mengubah penetapan kursus. Jika jumlah kursus jauh lebih besar:
- Anda mungkin akan menggunakan antarmuka pengguna yang berbeda untuk menampilkan kursus.
- Metode memanipulasi entitas gabungan untuk membuat atau menghapus hubungan tidak akan berubah.
Menambahkan kelas untuk mendukung halaman Instruktur Buat dan Edit
Buat Models/SchoolViewModels/AssignedCourseData.cs
dengan kode berikut:
namespace ContosoUniversity.Models.SchoolViewModels
{
public class AssignedCourseData
{
public int CourseID { get; set; }
public string Title { get; set; }
public bool Assigned { get; set; }
}
}
Kelas AssignedCourseData
berisi data untuk membuat kotak centang untuk kursus yang ditetapkan oleh instruktur.
Pages/Instructors/InstructorCoursesPageModel.cshtml.cs
Buat kelas dasar:
using ContosoUniversity.Data;
using ContosoUniversity.Models;
using ContosoUniversity.Models.SchoolViewModels;
using Microsoft.AspNetCore.Mvc.RazorPages;
using System.Collections.Generic;
using System.Linq;
namespace ContosoUniversity.Pages.Instructors
{
public class InstructorCoursesPageModel : PageModel
{
public List<AssignedCourseData> AssignedCourseDataList;
public void PopulateAssignedCourseData(SchoolContext context,
Instructor instructor)
{
var allCourses = context.Courses;
var instructorCourses = new HashSet<int>(
instructor.CourseAssignments.Select(c => c.CourseID));
AssignedCourseDataList = new List<AssignedCourseData>();
foreach (var course in allCourses)
{
AssignedCourseDataList.Add(new AssignedCourseData
{
CourseID = course.CourseID,
Title = course.Title,
Assigned = instructorCourses.Contains(course.CourseID)
});
}
}
public void UpdateInstructorCourses(SchoolContext context,
string[] selectedCourses, Instructor instructorToUpdate)
{
if (selectedCourses == null)
{
instructorToUpdate.CourseAssignments = new List<CourseAssignment>();
return;
}
var selectedCoursesHS = new HashSet<string>(selectedCourses);
var instructorCourses = new HashSet<int>
(instructorToUpdate.CourseAssignments.Select(c => c.Course.CourseID));
foreach (var course in context.Courses)
{
if (selectedCoursesHS.Contains(course.CourseID.ToString()))
{
if (!instructorCourses.Contains(course.CourseID))
{
instructorToUpdate.CourseAssignments.Add(
new CourseAssignment
{
InstructorID = instructorToUpdate.ID,
CourseID = course.CourseID
});
}
}
else
{
if (instructorCourses.Contains(course.CourseID))
{
CourseAssignment courseToRemove
= instructorToUpdate
.CourseAssignments
.SingleOrDefault(i => i.CourseID == course.CourseID);
context.Remove(courseToRemove);
}
}
}
}
}
}
InstructorCoursesPageModel
adalah kelas dasar yang akan Anda gunakan untuk model halaman Edit dan Buat. PopulateAssignedCourseData
membaca semua Course
entitas untuk mengisi AssignedCourseDataList
. Untuk setiap kursus, kode menetapkan CourseID
, judul, dan apakah instruktur ditetapkan ke kursus atau tidak. HashSet digunakan untuk membuat pencarian yang efisien.
Model halaman Edit Instruktur
Perbarui model halaman Edit instruktur dengan kode berikut:
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();
}
}
Kode sebelumnya menangani perubahan penetapan office.
Perbarui Tampilan instruktur 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");}
}
Catatan
Saat Anda menempelkan kode di Visual Studio, hentian baris diubah dengan cara yang merusak kode. Tekan Ctrl+Z satu kali untuk mengurungkan pemformatan otomatis. Ctrl+Z memperbaiki hentian baris sehingga terlihat seperti yang Anda lihat di sini. Indentasi tidak harus sempurna, tetapi @:</tr><tr>
baris , , @:<td>
@:</td>
, dan @:</tr>
masing-masing harus berada di satu baris seperti yang ditunjukkan. Dengan blok kode baru dipilih, tekan Tab tiga kali untuk mengjajarkan kode baru dengan kode yang ada. Pilih atau tinjau status bug ini dengan tautan ini.
Kode sebelumnya membuat tabel HTML yang memiliki tiga kolom. Setiap kolom memiliki kotak centang dan keterangan yang berisi nomor kursus dan judul. Semua kotak centang memiliki nama yang sama ("selectedCourses"). Menggunakan nama yang sama menginformasikan pengikat model untuk memperlakukannya sebagai grup. Atribut nilai dari setiap kotak centang diatur ke CourseID
. Saat halaman diposting, pengikat model meneruskan array yang terdiri dari CourseID
nilai hanya untuk kotak centang yang dipilih.
Ketika kotak centang awalnya dirender, kursus yang ditetapkan ke instruktur telah memeriksa atribut.
Jalankan aplikasi dan uji halaman Edit instruktur yang diperbarui. Ubah beberapa tugas kursus. Perubahan tercermin pada halaman Indeks.
Catatan: Pendekatan yang diambil di sini untuk mengedit data kursus instruktur berfungsi dengan baik ketika ada sejumlah kursus yang terbatas. Untuk koleksi yang jauh lebih besar, UI yang berbeda dan metode pembaruan yang berbeda akan lebih dapat digunakan dan efisien.
Memperbarui halaman Buat instruktur
Perbarui model halaman Buat instruktur dengan kode berikut:
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();
}
}
}
Kode sebelumnya mirip Pages/Instructors/Edit.cshtml.cs
dengan kode.
Perbarui halaman Buat Razor instruktur dengan markup berikut:
@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");}
}
Uji halaman Buat instruktur.
Memperbarui halaman Hapus
Perbarui model halaman Hapus dengan kode berikut:
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");
}
}
}
Kode sebelumnya membuat perubahan berikut:
Menggunakan pemuatan bersemangat untuk
CourseAssignments
properti navigasi.CourseAssignments
harus disertakan atau tidak dihapus saat instruktur dihapus. Untuk menghindari perlu membacanya, konfigurasikan penghapusan kaskade dalam database.Jika instruktur yang akan dihapus ditetapkan sebagai administrator departemen mana pun, menghapus penugasan instruktur dari departemen tersebut.
Sumber Daya Tambahan:
ASP.NET Core