Bölüm 7, Razor ASP.NET Core'da olan EF Core sayfalar - İlgili Verileri Güncelleştirme

Tom Dykstra, Jon P Smith ve Rick Anderson tarafından

Contoso University web uygulaması, ve Visual Studio kullanarak EF Core Sayfalar web uygulamalarının nasıl oluşturulacağını Razor gösterir. Öğretici serisi hakkında bilgi için ilk öğreticiye bakın.

Çözemediğiniz sorunlarla karşılaşırsanız, tamamlanmış uygulamayı indirin ve öğreticiyi izleyerek bu kodu oluşturduğunuz kodla karşılaştırın.

Bu öğreticide ilgili verilerin nasıl güncelleştirilecekleri gösterilmektedir. Aşağıdaki çizimlerde tamamlanan sayfalardan bazıları gösterilmektedir.

Course Edit pageInstructor Edit page

Kurs Oluşturma ve Düzenleme sayfalarını güncelleştirme

Kurs Oluşturma ve Düzenleme sayfalarının yapı iskelesi oluşturulmuş kodunda, öğesini intgösteren DepartmentIDbir Bölüm açılan listesi vardır. Açılan listede Departman adı gösterilmelidir, bu nedenle bu sayfaların her ikisinde de bölüm adları listesi gerekir. Bu listeyi sağlamak için Oluştur ve Düzenle sayfaları için bir temel sınıf kullanın.

Kurs Oluşturma ve Düzenleme için temel sınıf oluşturma

Aşağıdaki kodla bir Pages/Courses/DepartmentNamePageModel.cs dosya oluşturun:

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);
        }
    }
}

Yukarıdaki kod, bölüm adlarının listesini içeren bir SelectList oluşturur. belirtilirse selectedDepartment , bu bölüm içinde SelectListseçilir.

Sayfa modeli oluştur ve düzenle sınıfları'ndan DepartmentNamePageModeltüretilir.

Kurs Oluşturma sayfa modelini güncelleştirme

Bölüme bir Kurs atanır. Oluştur ve Düzenle sayfalarının temel sınıfı, bölümü seçmek için bir SelectList sağlar. öğesini kullanan SelectList açılan liste yabancı anahtar (FK) özelliğini ayarlar Course.DepartmentID . EF CoreCourse.DepartmentID gezinti özelliğini yüklemek için FK kullanırDepartment.

Create course

Aşağıdaki kodla güncelleştirin Pages/Courses/Create.cshtml.cs :

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();
        }
      }
}

Kod açıklamalarının İngilizce dışındaki dillere çevirisini görmek isterseniz, bunu bu GitHub tartışma konusunda bize bildirin.

Önceki kod:

  • 'den DepartmentNamePageModeltüretilir.
  • Fazla göndermeyi önlemek için kullanırTryUpdateModelAsync.
  • kaldırır ViewData["DepartmentID"]. DepartmentNameSLSelectList türü kesin olarak belirlenmiş bir modeldir ve sayfa tarafından Razor kullanılır. Kesin olarak yazılan modeller, zayıf yazılan modellere göre tercih edilir. Daha fazla bilgi için bkz . Zayıf yazılan veriler (ViewData ve ViewBag).

Kurs Oluşturma Razor sayfasını güncelleştirme

Aşağıdaki kodla güncelleştirin Pages/Courses/Create.cshtml :

@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");}
}

Yukarıdaki kod aşağıdaki değişiklikleri yapar:

  • başlık DepartmentID'den Department olarak değiştirir.
  • "ViewBag.DepartmentID" ile DepartmentNameSL değiştirir (temel sınıftan).
  • "Bölüm Seç" seçeneğini ekler. Bu değişiklik, ilk departman yerine henüz hiçbir bölüm seçilmediğinde açılan listede "Bölüm Seç" işlemini işler.
  • Bölüm seçilmediğinde bir doğrulama iletisi ekler.

Sayfa, Razor Etiket Seç Yardımcısı'nı kullanır:

<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>

Oluştur sayfasını test edin. Oluştur sayfası, departman kimliği yerine departman adını görüntüler.

Kurs Düzenleme sayfa modelini güncelleştirme

Aşağıdaki kodla güncelleştirin Pages/Courses/Edit.cshtml.cs :

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();
        }       
    }
}

Değişiklikler, Sayfa oluşturma modelinde yapılan değişikliklere benzer. Yukarıdaki kodda, PopulateDepartmentsDropDownList açılan listeden bu bölümü seçen bölüm kimliğini geçirir.

Kurs Düzenleme sayfasını güncelleştirme Razor

Aşağıdaki kodla güncelleştirin Pages/Courses/Edit.cshtml :

@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");}
}

Yukarıdaki kod aşağıdaki değişiklikleri yapar:

  • Kurs kimliğini görüntüler. Genellikle bir varlığın Birincil Anahtarı (PK) görüntülenmez. PK'ler genellikle kullanıcılar için anlamsızdır. Bu durumda, KURS numarası PK'dır.
  • Bölüm açılan listesinin başlık DepartmentID'den Department'a değiştirir.
  • "ViewBag.DepartmentID" değerini temel sınıftaki ile DepartmentNameSLdeğiştirir.

Sayfa, kurs numarası için gizli bir alan (<input type="hidden">) içerir. ile asp-for="Course.CourseID" etiket <label> yardımcısı eklemek, gizli alan gereksinimini ortadan kaldırmaz. <input type="hidden">, kullanıcı Kaydet'i seçtiğinde kurs numarasının gönderilen verilere dahil edilmesi için gereklidir.

Kurs sayfası modellerini güncelleştirme

AsNoTracking izleme gerekli olmadığında performansı artırabilir.

ve yöntemlerini ekleyerek AsNoTracking güncelleştirin:OnGetAsyncPages/Courses/Delete.cshtml.csPages/Courses/Details.cshtml.cs

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();
}

Kurs Razor sayfalarını güncelleştirme

Aşağıdaki kodla güncelleştirin Pages/Courses/Delete.cshtml :

@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>

Ayrıntılar sayfasında da aynı değişiklikleri yapın.

@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>

Kurs sayfalarını test edin

Oluşturma, düzenleme, ayrıntılar ve silme sayfalarını test edin.

Eğitmen oluşturma ve düzenleme sayfalarını güncelleştirme

Eğitmenler herhangi bir sayıda ders verebilir. Aşağıdaki görüntüde, bir dizi kurs onay kutusu içeren eğitmen Düzenleme sayfası gösterilmektedir.

Instructor Edit page with courses

Onay kutuları, eğitmenin atandığı kurslarda değişiklik yapmanızı sağlar. Veritabanındaki her kurs için bir onay kutusu görüntülenir. Eğitmenin atandığı kurslar seçilir. Kullanıcı, kurs ödevlerini değiştirmek için onay kutularını seçebilir veya temizleyebilir. Kurs sayısı çok daha fazlaysa farklı bir kullanıcı arabirimi daha iyi çalışabilir. Ancak burada gösterilen çoka çok ilişkiyi yönetme yöntemi değişmez. İlişki oluşturmak veya silmek için birleştirme varlığını işlemeniz gerekir.

Atanan kurs verileri için sınıf oluşturma

Aşağıdaki kodla oluşturun Models/SchoolViewModels/AssignedCourseData.cs :

namespace ContosoUniversity.Models.SchoolViewModels
{
    public class AssignedCourseData
    {
        public int CourseID { get; set; }
        public string Title { get; set; }
        public bool Assigned { get; set; }
    }
}

sınıfı, AssignedCourseData bir eğitmene atanan kurslar için onay kutularını oluşturmaya yönelik veriler içerir.

Eğitmen sayfa modeli temel sınıfı oluşturma

Pages/Instructors/InstructorCoursesPageModel.cs Temel sınıfı oluşturun:

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, Düzenleme ve Oluşturma sayfa modellerinin temel sınıfıdır. PopulateAssignedCourseDatadoldurulacak AssignedCourseDataListtüm Course varlıkları okur. Her kurs için kod , başlığını ve eğitmenin kursa atanıp atanmayacağını ayarlar CourseID. Karma Küme, verimli aramalar için kullanılır.

Ofis konumunu işleme

Düzenleme sayfasının işlemesi gereken bir diğer ilişki de Eğitmen varlığının varlıkla OfficeAssignment olan bire sıfır veya bir ilişkisidir. Eğitmenin kodu düzenlemesinin aşağıdaki senaryoları işlemesi gerekir:

  • Kullanıcı ofis atamasını temizlerse varlığı silin OfficeAssignment .
  • Kullanıcı bir ofis ataması girerse ve boşsa yeni OfficeAssignment bir varlık oluşturun.
  • Kullanıcı ofis atamasını değiştirirse varlığı güncelleştirin OfficeAssignment .

Eğitmen Düzenleme sayfa modelini güncelleştirme

Aşağıdaki kodla güncelleştirin Pages/Instructors/Edit.cshtml.cs :

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);
                    }
                }
            }
        }
    }
}

Önceki kod:

  • ve Courses gezinti özellikleri için hevesle yüklemeyi kullanarak veritabanından OfficeAssignment geçerli Instructor varlığı alır.
  • Alınan Instructor varlığı model bağlayıcısından alınan değerlerle Güncelleştirmeler. TryUpdateModelAsyncüst paylaşım yapılmasını engeller.
  • Ofis konumu boşsa null olarak ayarlanır Instructor.OfficeAssignment . Null olduğunda Instructor.OfficeAssignment , tablodaki OfficeAssignment ilgili satır silinir.
  • Görünüm modeli sınıfını kullanarak onay kutularıyla ilgili bilgi sağlamak için öğesini OnGetAsyncAssignedCourseData çağırırPopulateAssignedCourseData.
  • OnPostAsync Onay UpdateInstructorCourses kutularından düzenlenmekte olan Eğitmen varlığına bilgi uygulamak için çağrısı yapılır.
  • Başarısız olursa ve UpdateInstructorCourses çağrıları.PopulateAssignedCourseDataOnPostAsyncTryUpdateModelAsync Bu yöntem, bir hata iletisiyle yeniden görüntülendiğinde sayfaya girilen atanan kurs verilerini geri yüklemeyi çağırır.

Razor Sayfada Kurs varlıkları koleksiyonu olmadığından model bağlayıcısı gezinti özelliğini otomatik olarak güncelleştiremezCourses. Gezinti özelliğini güncelleştirmek için model bağlayıcısını Courses kullanmak yerine, bu işlem yeni UpdateInstructorCourses yöntemde yapılır. Bu nedenle, özelliğini model bağlamasının Courses dışında tutmanız gerekir. Bildirilen özelliklerle aşırı yüklemeyi kullandığınızdan ve Courses ekleme listesinde olmadığından bu, çağıran TryUpdateModelAsync kodda herhangi bir değişiklik gerektirmez.

Hiçbir onay kutusu seçilmediyse içindeki kod UpdateInstructorCourses boş bir koleksiyonla öğesini başlatır instructorToUpdate.Courses ve şunu döndürür:

if (selectedCourses == null)
{
    instructorToUpdate.Courses = new List<Course>();
    return;
}

Kod daha sonra veritabanındaki tüm kurslar arasında döngü oluşturur ve her kursu şu anda eğitmene atanmış olanlarla sayfada seçilenler arasında denetler. Verimli aramaları kolaylaştırmak için, ikinci iki koleksiyon nesnelerde HashSet depolanır.

Kursun onay kutusu seçiliyse ancak kurs gezinti özelliğinde Instructor.Courses değilse, kurs gezinti özelliğindeki koleksiyona eklenir.

if (selectedCoursesHS.Contains(course.CourseID.ToString()))
{
    if (!instructorCourses.Contains(course.CourseID))
    {
        instructorToUpdate.Courses.Add(course);
    }
}

Kursun onay kutusu seçili değilse ancak kurs gezinti özelliğindeyseInstructor.Courses, kurs gezinti özelliğinden kaldırılır.

else
{
    if (instructorCourses.Contains(course.CourseID))
    {
        var courseToRemove = instructorToUpdate.Courses.Single(
                                        c => c.CourseID == course.CourseID);
        instructorToUpdate.Courses.Remove(courseToRemove);
    }
}

Eğitmen Düzenleme sayfasını güncelleştirme Razor

Aşağıdaki kodla güncelleştirin Pages/Instructors/Edit.cshtml :

@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");}
}

Yukarıdaki kod, üç sütunu olan bir HTML tablosu oluşturur. Her sütunun bir onay kutusu ve kurs numarasını ve başlığını içeren bir başlık vardır. Onay kutularının tümü aynı ada ("selectedCourses") sahiptir. Aynı adın kullanılması, model bağlayıcısını bunları grup olarak ele almak için bilgilendirecektir. Her onay kutusunun değer özniteliği olarak CourseIDayarlanır. Sayfa deftere nakledildiğinde, model bağlayıcısı yalnızca seçilen onay kutularının değerlerinden CourseID oluşan bir dizi geçirir.

Onay kutuları başlangıçta işlendiğinde, eğitmene atanan kurslar seçilir.

Not: Eğitmen kurs verilerini düzenlemek için burada uygulanan yaklaşım, sınırlı sayıda kurs olduğunda iyi sonuç verir. Çok daha büyük koleksiyonlar için farklı bir kullanıcı arabirimi ve farklı bir güncelleştirme yöntemi daha kullanılabilir ve verimli olabilir.

Uygulamayı çalıştırın ve güncelleştirilmiş Eğitmenler Düzenleme sayfasını test edin. Bazı kurs ödevlerini değiştirin. Değişiklikler Dizin sayfasına yansıtılır.

Eğitmen Oluşturma sayfasını güncelleştirme

Eğitmen Oluşturma sayfası modelini ve Düzenle sayfasına benzer bir kodla güncelleştirin:

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();
        }
    }
}

Önceki kod:

  • Uyarı ve hata iletileri için günlüğe kaydetme ekler.

  • Çağrıları Load, tüm Kursları tek bir veritabanı çağrısında getirir. Küçük koleksiyonlar için bu, kullanılırken FindAsyncbir iyileştirmedir. FindAsync , veritabanına istekte bulunmadan izlenen varlığı döndürür.

    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)birleştirme tablosunu açıkça eşlemeden çoka çok ilişkileri kullanarak yeni Instructor bir oluşturur. EF 5.0'da çoka çok eklendi.

Eğitmen Oluşturma sayfasını test edin.

Eğitmen Oluşturma Razor sayfasını Düzenle sayfasına benzer bir kodla güncelleştirin:

@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");}
}

Eğitmen Silme sayfasını güncelleştirme

Aşağıdaki kodla güncelleştirin Pages/Instructors/Delete.cshtml.cs :

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");
        }
    }
}

Yukarıdaki kod aşağıdaki değişiklikleri yapar:

  • Gezinti özelliği için hevesle Courses yüklemeyi kullanır. Courses eklenmelidir veya eğitmen silindiğinde silinmez. Bunları okumak zorunda kalmamak için veritabanında art arda silmeyi yapılandırın.

  • Silinecek eğitmen herhangi bir bölümün yöneticisi olarak atanırsa, bu departmanlardan eğitmen atamasını kaldırır.

Uygulamayı çalıştırın ve Sil sayfasını test edin.

Sonraki adımlar

Bu öğreticide ilgili verilerin nasıl güncelleştirilecekleri gösterilmektedir. Aşağıdaki çizimlerde tamamlanan sayfalardan bazıları gösterilmektedir.

Course Edit pageInstructor Edit page

Kurs Oluşturma ve Düzenleme sayfalarını güncelleştirme

Kurs Oluşturma ve Düzenleme sayfalarının yapı iskelesi oluşturulmuş kodunda, Bölüm Kimliğini (tamsayı) gösteren bir Bölüm açılan listesi vardır. Açılan listede Departman adı gösterilmelidir, bu nedenle bu sayfaların her ikisinde de bölüm adları listesi gerekir. Bu listeyi sağlamak için Oluştur ve Düzenle sayfaları için bir temel sınıf kullanın.

Kurs Oluşturma ve Düzenleme için temel sınıf oluşturma

Aşağıdaki kodla bir Pages/Courses/DepartmentNamePageModel.cs dosya oluşturun:

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);
        }
    }
}

Yukarıdaki kod, bölüm adlarının listesini içeren bir SelectList oluşturur. belirtilirse selectedDepartment , bu bölüm içinde SelectListseçilir.

Sayfa modeli oluştur ve düzenle sınıfları'ndan DepartmentNamePageModeltüretilir.

Kurs Oluşturma sayfa modelini güncelleştirme

Bölüme bir Kurs atanır. Oluştur ve Düzenle sayfalarının temel sınıfı, bölümü seçmek için bir SelectList sağlar. öğesini kullanan SelectList açılan liste yabancı anahtar (FK) özelliğini ayarlar Course.DepartmentID . EF CoreCourse.DepartmentID gezinti özelliğini yüklemek için FK kullanırDepartment.

Create course

Aşağıdaki kodla güncelleştirin Pages/Courses/Create.cshtml.cs :

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();
        }
      }
}

Kod açıklamalarının İngilizce dışındaki dillere çevirisini görmek isterseniz, bunu bu GitHub tartışma konusunda bize bildirin.

Önceki kod:

  • 'den DepartmentNamePageModeltüretilir.
  • Fazla göndermeyi önlemek için kullanırTryUpdateModelAsync.
  • kaldırır ViewData["DepartmentID"]. DepartmentNameSL taban sınıfından kesin olarak belirlenmiş bir modeldir ve sayfa tarafından Razor kullanılır. Kesin olarak yazılan modeller, zayıf yazılan modellere göre tercih edilir. Daha fazla bilgi için bkz . Zayıf yazılan veriler (ViewData ve ViewBag).

Kurs Oluşturma Razor sayfasını güncelleştirme

Aşağıdaki kodla güncelleştirin Pages/Courses/Create.cshtml :

@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");}
}

Yukarıdaki kod aşağıdaki değişiklikleri yapar:

  • başlık DepartmentID'den Department olarak değiştirir.
  • "ViewBag.DepartmentID" ile DepartmentNameSL değiştirir (temel sınıftan).
  • "Bölüm Seç" seçeneğini ekler. Bu değişiklik, ilk departman yerine henüz hiçbir bölüm seçilmediğinde açılan listede "Bölüm Seç" işlemini işler.
  • Bölüm seçilmediğinde bir doğrulama iletisi ekler.

Sayfa, Razor Etiket Seç Yardımcısı'nı kullanır:

<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>

Oluştur sayfasını test edin. Oluştur sayfası, departman kimliği yerine departman adını görüntüler.

Kurs Düzenleme sayfa modelini güncelleştirme

Aşağıdaki kodla güncelleştirin Pages/Courses/Edit.cshtml.cs :

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();
        }       
    }
}

Değişiklikler, Sayfa oluşturma modelinde yapılan değişikliklere benzer. Yukarıdaki kodda, PopulateDepartmentsDropDownList açılan listeden bu bölümü seçen bölüm kimliğini geçirir.

Kurs Düzenleme sayfasını güncelleştirme Razor

Aşağıdaki kodla güncelleştirin Pages/Courses/Edit.cshtml :

@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");}
}

Yukarıdaki kod aşağıdaki değişiklikleri yapar:

  • Kurs kimliğini görüntüler. Genellikle bir varlığın Birincil Anahtarı (PK) görüntülenmez. PK'ler genellikle kullanıcılar için anlamsızdır. Bu durumda, KURS numarası PK'dır.
  • Bölüm açılan listesinin başlık DepartmentID'den Department'a değiştirir.
  • "ViewBag.DepartmentID" ile DepartmentNameSL değiştirir (temel sınıftan).

Sayfa, kurs numarası için gizli bir alan (<input type="hidden">) içerir. ile asp-for="Course.CourseID" etiket <label> yardımcısı eklemek, gizli alan gereksinimini ortadan kaldırmaz. <input type="hidden">, kullanıcı Kaydet'e tıkladığında kurs numarasının gönderilen verilere dahil edilmesi için gereklidir.

Kurs Ayrıntıları ve Silme sayfalarını güncelleştirme

AsNoTracking izleme gerekli olmadığında performansı artırabilir.

Kurs sayfası modellerini güncelleştirme

eklemek AsNoTrackingiçin aşağıdaki kodla güncelleştirinPages/Courses/Delete.cshtml.cs:

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");
        }
    }
}

Dosyada Pages/Courses/Details.cshtml.cs aynı değişikliği yapın:

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();
        }
    }
}

Kurs Razor sayfalarını güncelleştirme

Aşağıdaki kodla güncelleştirin Pages/Courses/Delete.cshtml :

@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>

Ayrıntılar sayfasında da aynı değişiklikleri yapın.

@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>

Kurs sayfalarını test edin

Oluşturma, düzenleme, ayrıntılar ve silme sayfalarını test edin.

Eğitmen oluşturma ve düzenleme sayfalarını güncelleştirme

Eğitmenler herhangi bir sayıda ders verebilir. Aşağıdaki görüntüde, bir dizi kurs onay kutusu içeren eğitmen Düzenleme sayfası gösterilmektedir.

Instructor Edit page with courses

Onay kutuları, eğitmenin atandığı kurslarda değişiklik yapmanızı sağlar. Veritabanındaki her kurs için bir onay kutusu görüntülenir. Eğitmenin atandığı kurslar seçilir. Kullanıcı, kurs ödevlerini değiştirmek için onay kutularını seçebilir veya temizleyebilir. Kurs sayısı çok daha fazlaysa farklı bir kullanıcı arabirimi daha iyi çalışabilir. Ancak burada gösterilen çoka çok ilişkiyi yönetme yöntemi değişmez. İlişki oluşturmak veya silmek için birleştirme varlığını işlemeniz gerekir.

Atanan kurs verileri için sınıf oluşturma

Aşağıdaki kodla oluşturun Models/SchoolViewModels/AssignedCourseData.cs :

namespace ContosoUniversity.Models.SchoolViewModels
{
    public class AssignedCourseData
    {
        public int CourseID { get; set; }
        public string Title { get; set; }
        public bool Assigned { get; set; }
    }
}

sınıfı, AssignedCourseData bir eğitmene atanan kurslar için onay kutularını oluşturmaya yönelik veriler içerir.

Eğitmen sayfa modeli temel sınıfı oluşturma

Pages/Instructors/InstructorCoursesPageModel.cs Temel sınıfı oluşturun:

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, Düzenle ve Oluştur sayfa modelleri için kullanacağınız temel sınıftır. PopulateAssignedCourseDatadoldurulacak AssignedCourseDataListtüm Course varlıkları okur. Her kurs için kod , başlığını ve eğitmenin kursa atanıp atanmayacağını ayarlar CourseID. Karma Küme, verimli aramalar için kullanılır.

Razor Sayfada Kurs varlıkları koleksiyonu olmadığından model bağlayıcısı gezinti özelliğini otomatik olarak güncelleştiremezCourseAssignments. Gezinti özelliğini güncelleştirmek için model bağlayıcısını CourseAssignments kullanmak yerine bunu yeni UpdateInstructorCourses yöntemde yaparsınız. Bu nedenle, özelliğini model bağlamasının CourseAssignments dışında tutmanız gerekir. Bildirilen özelliklerle aşırı yüklemeyi kullandığınızdan ve CourseAssignments ekleme listesinde olmadığından bu, çağıran TryUpdateModel kodda herhangi bir değişiklik gerektirmez.

Onay kutusu seçilmediyse içindeki kod UpdateInstructorCourses , gezinti özelliğini boş bir koleksiyonla başlatır CourseAssignments ve şunu döndürür:

if (selectedCourses == null)
{
    instructorToUpdate.CourseAssignments = new List<CourseAssignment>();
    return;
}

Kod daha sonra veritabanındaki tüm kurslar arasında döngü oluşturur ve her kursu şu anda eğitmene atanmış olanlarla sayfada seçilenler arasında denetler. Verimli aramaları kolaylaştırmak için, ikinci iki koleksiyon nesnelerde HashSet depolanır.

Kursun onay kutusu seçiliyse ancak kurs gezinti özelliğinde Instructor.CourseAssignments değilse, kurs gezinti özelliğindeki koleksiyona eklenir.

if (selectedCoursesHS.Contains(course.CourseID.ToString()))
{
    if (!instructorCourses.Contains(course.CourseID))
    {
        instructorToUpdate.CourseAssignments.Add(
            new CourseAssignment
            {
                InstructorID = instructorToUpdate.ID,
                CourseID = course.CourseID
            });
    }
}

Kursun onay kutusu seçili değilse ancak kurs gezinti özelliğindeyse Instructor.CourseAssignments , kurs gezinti özelliğinden kaldırılır.

else
{
    if (instructorCourses.Contains(course.CourseID))
    {
        CourseAssignment courseToRemove
            = instructorToUpdate
                .CourseAssignments
                .SingleOrDefault(i => i.CourseID == course.CourseID);
        context.Remove(courseToRemove);
    }
}

Ofis konumunu işleme

Düzenleme sayfasının işlemesi gereken bir diğer ilişki de Eğitmen varlığının varlıkla OfficeAssignment olan bire sıfır veya bir ilişkisidir. Eğitmenin kodu düzenlemesinin aşağıdaki senaryoları işlemesi gerekir:

  • Kullanıcı ofis atamasını temizlerse varlığı silin OfficeAssignment .
  • Kullanıcı bir ofis ataması girerse ve boşsa yeni OfficeAssignment bir varlık oluşturun.
  • Kullanıcı ofis atamasını değiştirirse varlığı güncelleştirin OfficeAssignment .

Eğitmen Düzenleme sayfa modelini güncelleştirme

Aşağıdaki kodla güncelleştirin Pages/Instructors/Edit.cshtml.cs :

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();
        }
    }
}

Önceki kod:

  • , CourseAssignmentve CourseAssignment.Course gezinti özellikleri için istekli yükleme kullanarak veritabanından OfficeAssignmentgeçerli Instructor varlığı alır.
  • Alınan Instructor varlığı model bağlayıcısından alınan değerlerle Güncelleştirmeler. TryUpdateModelüst paylaşım yapılmasını engeller.
  • Ofis konumu boşsa null olarak ayarlanır Instructor.OfficeAssignment . Null olduğunda Instructor.OfficeAssignment , tablodaki OfficeAssignment ilgili satır silinir.
  • Görünüm modeli sınıfını kullanarak onay kutularıyla ilgili bilgi sağlamak için öğesini OnGetAsyncAssignedCourseData çağırırPopulateAssignedCourseData.
  • OnPostAsync Onay UpdateInstructorCourses kutularından düzenlenmekte olan Eğitmen varlığına bilgi uygulamak için çağrısı yapılır.
  • Başarısız olursa ve UpdateInstructorCourses çağrıları.PopulateAssignedCourseDataOnPostAsyncTryUpdateModel Bu yöntem, bir hata iletisiyle yeniden görüntülendiğinde sayfaya girilen atanan kurs verilerini geri yüklemeyi çağırır.

Eğitmen Düzenleme sayfasını güncelleştirme Razor

Aşağıdaki kodla güncelleştirin Pages/Instructors/Edit.cshtml :

@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");}
}

Yukarıdaki kod, üç sütunu olan bir HTML tablosu oluşturur. Her sütunun bir onay kutusu ve kurs numarasını ve başlığını içeren bir başlık vardır. Onay kutularının tümü aynı ada ("selectedCourses") sahiptir. Aynı adın kullanılması, model bağlayıcısını bunları grup olarak ele almak için bilgilendirecektir. Her onay kutusunun değer özniteliği olarak CourseIDayarlanır. Sayfa deftere nakledildiğinde, model bağlayıcısı yalnızca seçilen onay kutularının değerlerinden CourseID oluşan bir dizi geçirir.

Onay kutuları başlangıçta işlendiğinde, eğitmene atanan kurslar seçilir.

Not: Eğitmen kurs verilerini düzenlemek için burada uygulanan yaklaşım, sınırlı sayıda kurs olduğunda iyi sonuç verir. Çok daha büyük koleksiyonlar için farklı bir kullanıcı arabirimi ve farklı bir güncelleştirme yöntemi daha kullanılabilir ve verimli olabilir.

Uygulamayı çalıştırın ve güncelleştirilmiş Eğitmenler Düzenleme sayfasını test edin. Bazı kurs ödevlerini değiştirin. Değişiklikler Dizin sayfasına yansıtılır.

Eğitmen Oluşturma sayfasını güncelleştirme

Eğitmen Oluşturma sayfası modelini ve Razor sayfasını Düzenle sayfasına benzer bir kodla güncelleştirin:

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");}
}

Eğitmen Oluşturma sayfasını test edin.

Eğitmen Silme sayfasını güncelleştirme

Aşağıdaki kodla güncelleştirin Pages/Instructors/Delete.cshtml.cs :

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");
        }
    }
}

Yukarıdaki kod aşağıdaki değişiklikleri yapar:

  • Gezinti özelliği için hevesle CourseAssignments yüklemeyi kullanır. CourseAssignments eklenmelidir veya eğitmen silindiğinde silinmez. Bunları okumak zorunda kalmamak için veritabanında art arda silmeyi yapılandırın.

  • Silinecek eğitmen herhangi bir bölümün yöneticisi olarak atanırsa, bu departmanlardan eğitmen atamasını kaldırır.

Uygulamayı çalıştırın ve Sil sayfasını test edin.

Sonraki adımlar

Bu öğreticide ilgili verilerin güncelleştirilmesi gösterilmektedir. Çözemediğiniz sorunlarla karşılaşırsanız tamamlanmış uygulamayı indirin veya görüntüleyin.İndirme yönergeleri.

Aşağıdaki çizimlerde tamamlanan sayfalardan bazıları gösterilmektedir.

Course Edit pageInstructor Edit page

Kurs oluşturma ve düzenleme sayfalarını inceleyin ve test edin. Yeni bir kurs oluşturun. Bölüm, adıyla değil birincil anahtarıyla (tamsayı) seçilir. Yeni kursu düzenleyin. Testi tamamladığınızda yeni kursu silin.

Ortak kodu paylaşmak için temel sınıf oluşturma

Kurslar/Oluştur ve Kurslar/Düzenle sayfalarının her birinin bir bölüm adı listesi gerekir. Pages/Courses/DepartmentNamePageModel.cshtml.cs Oluştur ve Düzenle sayfaları için temel sınıfı oluşturun:

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);
        }
    }
}

Yukarıdaki kod, bölüm adlarının listesini içeren bir SelectList oluşturur. belirtilirse selectedDepartment , bu bölüm içinde SelectListseçilir.

Sayfa modeli oluştur ve düzenle sınıfları'ndan DepartmentNamePageModeltüretilir.

Kurs Sayfalarını Özelleştirme

Yeni bir kurs varlığı oluşturulduğunda, var olan bir bölümle ilişkisi olmalıdır. Kurs oluştururken bölüm eklemek için Oluştur ve Düzenle temel sınıfı, bölümü seçmeye yönelik bir açılan liste içerir. Açılan liste yabancı anahtar (FK) özelliğini ayarlar Course.DepartmentID . EF CoreCourse.DepartmentID gezinti özelliğini yüklemek için FK kullanırDepartment.

Create course

Sayfa modeli oluştur'u aşağıdaki kodla güncelleştirin:

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();
        }
      }
}

Önceki kod:

  • 'den DepartmentNamePageModeltüretilir.
  • Fazla göndermeyi önlemek için kullanırTryUpdateModelAsync.
  • ViewData["DepartmentID"] ile DepartmentNameSL değiştirir (temel sınıftan).

ViewData["DepartmentID"] , kesin olarak yazılan DepartmentNameSLile değiştirilir. Kesin olarak yazılan modeller, zayıf yazılan modellere göre tercih edilir. Daha fazla bilgi için bkz . Zayıf yazılan veriler (ViewData ve ViewBag).

Kurs Oluşturma sayfasını güncelleştirme

Aşağıdaki kodla güncelleştirin Pages/Courses/Create.cshtml :

@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");}
}

Yukarıdaki işaretleme aşağıdaki değişiklikleri yapar:

  • başlık DepartmentID'den Department olarak değiştirir.
  • "ViewBag.DepartmentID" ile DepartmentNameSL değiştirir (temel sınıftan).
  • "Bölüm Seç" seçeneğini ekler. Bu değişiklik, ilk bölüm yerine "Bölüm Seç" işlemini işler.
  • Bölüm seçilmediğinde bir doğrulama iletisi ekler.

Sayfa, Razor Etiket Seç Yardımcısı'nı kullanır:

<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>

Oluştur sayfasını test edin. Oluştur sayfası, departman kimliği yerine departman adını görüntüler.

Kursları Düzenle sayfasını güncelleştirin.

içindeki Pages/Courses/Edit.cshtml.cs kodu aşağıdaki kodla değiştirin:

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();
        }       
    }
}

Değişiklikler, Sayfa oluşturma modelinde yapılan değişikliklere benzer. Yukarıdaki kodda, PopulateDepartmentsDropDownList açılan listede belirtilen bölümü seçen departman kimliğini geçirir.

Aşağıdaki işaretlemeyle güncelleştirin Pages/Courses/Edit.cshtml :

@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");}
}

Yukarıdaki işaretleme aşağıdaki değişiklikleri yapar:

  • Kurs kimliğini görüntüler. Genellikle bir varlığın Birincil Anahtarı (PK) görüntülenmez. PK'ler genellikle kullanıcılar için anlamsızdır. Bu durumda, KURS numarası PK'dır.
  • başlık DepartmentID'den Department olarak değiştirir.
  • "ViewBag.DepartmentID" ile DepartmentNameSL değiştirir (temel sınıftan).

Sayfa, kurs numarası için gizli bir alan (<input type="hidden">) içerir. ile asp-for="Course.CourseID" etiket <label> yardımcısı eklemek, gizli alan gereksinimini ortadan kaldırmaz. <input type="hidden">, kullanıcı Kaydet'e tıkladığında kurs numarasının gönderilen verilere dahil edilmesi için gereklidir.

Güncelleştirilmiş kodu test edin. Kurs oluşturma, düzenleme ve silme.

Ayrıntılar ve Silme sayfa modellerine AsNoTracking ekleme

AsNoTracking izleme gerekli olmadığında performansı artırabilir. Sil ve Ayrıntılar sayfa modeline ekleyin AsNoTracking . Aşağıdaki kod güncelleştirilmiş Sayfayı sil modelini gösterir:

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");
    }
}

Dosyasındaki OnGetAsync yöntemini güncelleştirin Pages/Courses/Details.cshtml.cs :

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();
}

Silme ve Ayrıntılar sayfalarını değiştirme

Sil Razor sayfasını aşağıdaki işaretlemeyle güncelleştirin:

@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>

Ayrıntılar sayfasında da aynı değişiklikleri yapın.

Kurs sayfalarını test edin

Oluşturma, düzenleme, ayrıntılar ve silmeyi test edin.

Eğitmen sayfalarını güncelleştirme

Aşağıdaki bölümlerde eğitmen sayfaları güncelleştirilmektedir.

Ofis konumu ekleme

Eğitmen kaydını düzenlerken, eğitmenin ofis ödevini güncelleştirmek isteyebilirsiniz. Varlığın Instructor varlıkla OfficeAssignment bire sıfır veya bir ilişkisi vardır. Eğitmen kodu aşağıdakileri işlemelidir:

  • Kullanıcı ofis atamasını temizlerse varlığı silin OfficeAssignment .
  • Kullanıcı bir ofis ataması girerse ve boşsa yeni OfficeAssignment bir varlık oluşturun.
  • Kullanıcı ofis atamasını değiştirirse varlığı güncelleştirin OfficeAssignment .

Eğitmenleri Sayfa modelini düzenle'yi aşağıdaki kodla güncelleştirin:

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");

    }
}

Önceki kod:

  • Gezinti özelliği için istekli yükleme kullanarak veritabanından OfficeAssignment geçerli Instructor varlığı alır.
  • Alınan Instructor varlığı model bağlayıcısından alınan değerlerle Güncelleştirmeler. TryUpdateModelüst paylaşım yapılmasını engeller.
  • Ofis konumu boşsa null olarak ayarlanır Instructor.OfficeAssignment . Null olduğunda Instructor.OfficeAssignment , tablodaki OfficeAssignment ilgili satır silinir.

Eğitmen Düzenleme sayfasını güncelleştirme

Office konumuyla güncelleştirin Pages/Instructors/Edit.cshtml :

@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");}
}

Eğitmenlerin ofis konumunu değiştirebildiğinizi doğrulayın.

Eğitmen Düzenleme sayfasına Kurs ödevleri ekleme

Eğitmenler herhangi bir sayıda ders verebilir. Bu bölümde, kurs ödevlerini değiştirme özelliğini ekleyebilirsiniz. Aşağıdaki görüntüde güncelleştirilmiş eğitmen Düzenleme sayfası gösterilmektedir:

Instructor Edit page with courses

Course ve Instructor çoka çok ilişkisine sahiptir. İlişki eklemek ve kaldırmak için birleştirme varlık kümesine CourseAssignments varlık ekleyip kaldırabilirsiniz.

onay kutuları, eğitmenin atandığı kurslarda değişiklik yapmanızı sağlar. Veritabanındaki her kurs için bir onay kutusu görüntülenir. Eğitmenin atandığı kurslar kontrol edilir. Kullanıcı, kurs ödevlerini değiştirmek için onay kutularını seçebilir veya temizleyebilir. Ders sayısı çok daha fazlaysa:

  • Büyük olasılıkla kursları görüntülemek için farklı bir kullanıcı arabirimi kullanırsınız.
  • İlişki oluşturmak veya silmek için birleştirme varlığını düzenleme yöntemi değişmez.

Eğitmen sayfaları oluşturma ve düzenleme desteği için sınıf ekleme

Aşağıdaki kodla oluşturun Models/SchoolViewModels/AssignedCourseData.cs :

namespace ContosoUniversity.Models.SchoolViewModels
{
    public class AssignedCourseData
    {
        public int CourseID { get; set; }
        public string Title { get; set; }
        public bool Assigned { get; set; }
    }
}

sınıfı, AssignedCourseData eğitmen tarafından atanan derslerin onay kutularını oluşturmaya yönelik veriler içerir.

Pages/Instructors/InstructorCoursesPageModel.cshtml.cs Temel sınıfı oluşturun:

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, Düzenle ve Oluştur sayfa modelleri için kullanacağınız temel sınıftır. PopulateAssignedCourseDatadoldurulacak AssignedCourseDataListtüm Course varlıkları okur. Her kurs için kod , başlığını ve eğitmenin kursa atanıp atanmayacağını ayarlar CourseID. Karma Küme, verimli aramalar oluşturmak için kullanılır.

Eğitmenler Sayfa modelini düzenle

Eğitmen Sayfa modelini düzenle'yi aşağıdaki kodla güncelleştirin:

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();
    }
}

Yukarıdaki kod, office ataması değişikliklerini işler.

Eğitmen Razor Görünümünü güncelleştirin:

@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");}
}

Dekont

Kodu Visual Studio'ya yapıştırdığınızda satır sonları kodu bozabilecek şekilde değiştirilir. Otomatik biçimlendirmeyi geri almak için Ctrl+Z tuşlarına bir kez basın. Ctrl+Z tuşları satır sonlarını burada gördüğünüz gibi görünecek şekilde düzeltir. Girintinin mükemmel olması gerekmez, ancak @:</tr><tr>, @:<td>, @:</td>ve @:</tr> satırlarının her birinin gösterildiği gibi tek bir satırda olması gerekir. Yeni kod bloğu seçiliyken, yeni kodu var olan kodla aynı hizaya getirmek için Sekme tuşuna üç kez basın. Bu bağlantıyla bu hatanın durumunu oy verin veya gözden geçirin.

Yukarıdaki kod, üç sütunu olan bir HTML tablosu oluşturur. Her sütunun bir onay kutusu ve kurs numarasını ve başlığını içeren bir başlık vardır. Onay kutularının tümü aynı ada ("selectedCourses") sahiptir. Aynı adın kullanılması, model bağlayıcısını bunları grup olarak ele almak için bilgilendirecektir. Her onay kutusunun değer özniteliği olarak CourseIDayarlanır. Sayfa deftere nakledildiğinde, model bağlayıcısı yalnızca seçilen onay kutularının değerlerinden CourseID oluşan bir dizi geçirir.

Onay kutuları başlangıçta işlendiğinde, eğitmene atanan kurslar öznitelikleri denetledi.

Uygulamayı çalıştırın ve güncelleştirilmiş eğitmenler Düzenleme sayfasını test edin. Bazı kurs ödevlerini değiştirin. Değişiklikler Dizin sayfasına yansıtılır.

Not: Eğitmen kurs verilerini düzenlemek için burada uygulanan yaklaşım, sınırlı sayıda kurs olduğunda iyi sonuç verir. Çok daha büyük koleksiyonlar için farklı bir kullanıcı arabirimi ve farklı bir güncelleştirme yöntemi daha kullanılabilir ve verimli olabilir.

Eğitmenler Oluşturma sayfasını güncelleştirme

Eğitmen Oluşturma sayfası modelini aşağıdaki kodla güncelleştirin:

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();
        }
    }
}

Yukarıdaki kod, koda Pages/Instructors/Edit.cshtml.cs benzer.

Eğitmen Oluşturma Razor sayfasını aşağıdaki işaretlemeyle güncelleştirin:

@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");}
}

Eğitmen Oluşturma sayfasını test edin.

Sil sayfasını güncelleştirme

Sayfayı sil modelini aşağıdaki kodla güncelleştirin:

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");
        }
    }
}

Yukarıdaki kod aşağıdaki değişiklikleri yapar:

  • Gezinti özelliği için hevesle CourseAssignments yüklemeyi kullanır. CourseAssignments eklenmelidir veya eğitmen silindiğinde silinmez. Bunları okumak zorunda kalmamak için veritabanında art arda silmeyi yapılandırın.

  • Silinecek eğitmen herhangi bir bölümün yöneticisi olarak atanırsa, bu departmanlardan eğitmen atamasını kaldırır.

Ek kaynaklar