Aracılığıyla paylaş


Bölüm 6, Razor ASP.NET Çekirdekte olan EF Core sayfalar - İlgili Verileri Okuma

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 okunduğu ve görüntüleneceği gösterilmektedir. İlgili veriler, gezinti özelliklerine yüklenen verilerdir EF Core .

Aşağıdaki çizimlerde bu öğreticinin tamamlanmış sayfaları gösterilmektedir:

Courses Index page

Instructors Index page

İstekli, açık ve gecikmeli yükleme

Bir varlığın EF Core gezinti özelliklerine ilgili verileri yüklemenin birkaç yolu vardır:

  • İstekli yükleme. İstekli yükleme, bir varlık türüne yönelik bir sorgunun ilgili varlıkları da yüklediğinde gerçekleşir. Bir varlık okunduğunda ilgili verileri alınır. Bu genellikle gereken tüm verileri alan tek bir birleştirme sorgusuyla sonuçlanmıştır. EF Core bazı istekli yükleme türleri için birden çok sorgu yayımlar. Birden çok sorgu oluşturmak, büyük bir tek sorgudan daha verimli olabilir. İstekli yükleme ve ThenInclude yöntemleriyle Include belirtilir.

    Eager loading example

    Bir koleksiyon gezintisi eklendiğinde, Eager yükleme birden çok sorgu gönderir:

    • Ana sorgu için bir sorgu
    • Yük ağacındaki her "edge" koleksiyonu için bir sorgu.
  • ile Loadayrı sorgular: Veriler ayrı sorgularda alınabilir ve EF Core gezinti özelliklerini "düzeltir". "Düzeltmeler", gezinti özelliklerini otomatik olarak dolduran EF Core anlamına gelir. ile Load ayrı sorgular, istekli yüklemeden çok açıkça yüklemeye benzer.

    Separate queries example

    Not:EF Core Daha önce bağlam örneğine yüklenmiş olan diğer varlıklara gezinti özelliklerini otomatik olarak düzeltir. Bir gezinti özelliğinin verileri açıkça dahil edilmese bile, ilgili varlıkların bazıları veya tümü önceden yüklenmişse özellik yine de doldurulabilir.

  • Açık yükleme. Varlık ilk kez okunduğunda ilgili veriler alınmaz. Gerekli olduğunda ilgili verileri almak için kod yazılmalıdır. Ayrı sorgularla açık yükleme, veritabanına birden çok sorgu gönderilmesine neden olur. Açık yükleme ile kod yüklenecek gezinti özelliklerini belirtir. Load Açık yükleme yapmak için yöntemini kullanın. Örnek:

    Explicit loading example

  • Yavaş yükleme. Varlık ilk kez okunduğunda ilgili veriler alınmaz. Bir gezinti özelliğine ilk kez erişildiğinde, bu gezinti özelliği için gereken veriler otomatik olarak alınır. Bir gezinti özelliğine ilk kez her erişildiğinde veritabanına bir sorgu gönderilir. Gecikmeli yükleme, örneğin geliştiriciler N+1 sorguları kullandığında performansa zarar verebilir. N+1 sorguları bir üst öğe yükler ve alt öğeler arasında numaralandırır.

Kurs sayfaları oluşturma

Varlık, Course ilgili Department varlığı içeren bir gezinti özelliği içerir.

Course.Department

Bir kurs için atanan bölümün adını görüntülemek için:

  • İlgili Department varlığı gezinti özelliğine Course.Department yükleyin.
  • Varlığın DepartmentName özelliğinden adı alın.

yapı iskelesi kursu sayfaları

  • Aşağıdaki özel durumlarla birlikte yapı iskelesi Öğrenci sayfalarındaki yönergeleri izleyin:

    • Sayfalar/Kurslar klasörü oluşturun.
    • Model sınıfı için kullanın Course .
    • Yeni bir tane oluşturmak yerine mevcut bağlam sınıfını kullanın.
  • yöntemini açın Pages/Courses/Index.cshtml.cs ve inceleyin OnGetAsync . yapı iskelesi altyapısı gezinti özelliği için istekli yükleme belirtti Department . Include yöntemi, istekli yüklemeyi belirtir.

  • Uygulamayı çalıştırın ve Kurslar bağlantısını seçin. Departman sütunu, kullanışlı olmayan öğesini görüntüler DepartmentID.

Bölüm adını görüntüleme

Pages/Courses/Index.cshtml.cs dosyasını aşağıdaki kodla güncelleştirin:

using ContosoUniversity.Models;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.EntityFrameworkCore;
using System.Collections.Generic;
using System.Threading.Tasks;

namespace ContosoUniversity.Pages.Courses
{
    public class IndexModel : PageModel
    {
        private readonly ContosoUniversity.Data.SchoolContext _context;

        public IndexModel(ContosoUniversity.Data.SchoolContext context)
        {
            _context = context;
        }

        public IList<Course> Courses { get; set; }

        public async Task OnGetAsync()
        {
            Courses = await _context.Courses
                .Include(c => c.Department)
                .AsNoTracking()
                .ToListAsync();
        }
    }
}

Yukarıdaki kod özelliğini olarak Courses değiştirir Course ve eklerAsNoTracking.

İzlemesiz sorgular, sonuçlar salt okunur bir senaryoda kullanıldığında kullanışlıdır. Değişiklik izleme bilgilerini ayarlamaya gerek olmadığından, bunlar genellikle daha hızlı yürütülür. Veritabanından alınan varlıkların güncelleştirilmiş olması gerekmiyorsa, izleme sorgusunun izleme sorgusundan daha iyi performans gösterme olasılığı yüksektir.

Bazı durumlarda izleme sorgusu, izleme olmayan sorgudan daha verimlidir. Daha fazla bilgi için bkz . İzleme ve İzleme Olmayan Sorgular. Yukarıdaki kodda, AsNoTracking varlıklar geçerli bağlamda güncelleştirilemediğinden çağrılır.

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

@page
@model ContosoUniversity.Pages.Courses.IndexModel

@{
    ViewData["Title"] = "Courses";
}

<h1>Courses</h1>

<p>
    <a asp-page="Create">Create New</a>
</p>
<table class="table">
    <thead>
        <tr>
            <th>
                @Html.DisplayNameFor(model => model.Courses[0].CourseID)
            </th>
            <th>
                @Html.DisplayNameFor(model => model.Courses[0].Title)
            </th>
            <th>
                @Html.DisplayNameFor(model => model.Courses[0].Credits)
            </th>
            <th>
                @Html.DisplayNameFor(model => model.Courses[0].Department)
            </th>
            <th></th>
        </tr>
    </thead>
    <tbody>
@foreach (var item in Model.Courses)
{
        <tr>
            <td>
                @Html.DisplayFor(modelItem => item.CourseID)
            </td>
            <td>
                @Html.DisplayFor(modelItem => item.Title)
            </td>
            <td>
                @Html.DisplayFor(modelItem => item.Credits)
            </td>
            <td>
                @Html.DisplayFor(modelItem => item.Department.Name)
            </td>
            <td>
                <a asp-page="./Edit" asp-route-id="@item.CourseID">Edit</a> |
                <a asp-page="./Details" asp-route-id="@item.CourseID">Details</a> |
                <a asp-page="./Delete" asp-route-id="@item.CourseID">Delete</a>
            </td>
        </tr>
}
    </tbody>
</table>

yapı iskelesi oluşturulmuş kodda aşağıdaki değişiklikler yapılmıştır:

  • Course Özellik adı olarak Coursesdeğiştirildi.

  • Özellik değerini gösteren CourseID bir Sayı sütunu eklendi. Varsayılan olarak, birincil anahtarlar son kullanıcılar için anlamlı olmadığından yapı iskelesi oluşturmaz. Ancak, bu durumda birincil anahtar anlamlıdır.

  • Departman adını görüntülemek için Department sütunu değiştirildi. Kod, gezinti özelliğine Department yüklenen varlığın Department özelliğini görüntülerName:

    @Html.DisplayFor(modelItem => item.Department.Name)
    

Uygulamayı çalıştırın ve bölüm adlarını içeren listeyi görmek için Kurslar sekmesini seçin.

Courses Index page

yöntemi, OnGetAsync yöntemiyle Include ilgili verileri yükler. Select yöntemi, yalnızca gerekli olan ilgili verileri yükleyen bir alternatiftir. gibi Department.Name tek öğeler için bir SQL INNER JOINkullanır. Koleksiyonlar için başka bir veritabanı erişimi kullanır, ancak koleksiyonlardaki Include işleci de kullanır.

Aşağıdaki kod yöntemiyle Select ilgili verileri yükler:

public IList<CourseViewModel> CourseVM { get; set; }

public async Task OnGetAsync()
{
    CourseVM = await _context.Courses
    .Select(p => new CourseViewModel
    {
        CourseID = p.CourseID,
        Title = p.Title,
        Credits = p.Credits,
        DepartmentName = p.Department.Name
    }).ToListAsync();
}

Yukarıdaki kod herhangi bir varlık türü döndürmez, bu nedenle izleme yapılmaz. EF izleme hakkında daha fazla bilgi için bkz . İzleme ve İzleme Olmayan Sorgular.

:CourseViewModel

public class CourseViewModel
{
    public int CourseID { get; set; }
    public string Title { get; set; }
    public int Credits { get; set; }
    public string DepartmentName { get; set; }
}

Sayfaların tamamı için bkz. IndexSelectModel.Razor

Eğitmen sayfaları oluşturma

Bu bölüm, Eğitmen sayfalarının iskelesini oluşturur ve eğitmen dizini sayfasına ilgili Kurslar ve Kayıtlar ekler.

Instructors Index page

Bu sayfa, ilgili verileri aşağıdaki yollarla okur ve görüntüler:

  • Eğitmen listesi, varlıktan OfficeAssignment (önceki görüntüde Office) ilgili verileri görüntüler. Instructor ve OfficeAssignment varlıkları bire sıfıra veya bir ilişkisindedir. Varlıklar için OfficeAssignment istekli yükleme kullanılır. İstekli yükleme genellikle ilgili verilerin görüntülenmesi gerektiğinde daha verimli olur. Bu durumda, eğitmenler için ofis ödevleri görüntülenir.
  • Kullanıcı bir eğitmen seçtiğinde ilgili Course varlıklar görüntülenir. Instructor ve Course varlıkları çoka çok ilişkisindedir. Hevesle yükleme, varlıklar ve ilgili Department varlıkları için Course kullanılır. Bu durumda, yalnızca seçilen eğitmene yönelik kurslar gerektiğinden ayrı sorgular daha verimli olabilir. Bu örnekte, gezinti özelliklerindeki varlıklarda gezinti özellikleri için istekli yüklemenin nasıl kullanılacağı gösterilmektedir.
  • Kullanıcı bir kurs seçtiğinde, varlıktan Enrollments ilgili veriler görüntülenir. Önceki resimde öğrenci adı ve notu görüntülenir. Course ve Enrollment varlıkları bire çok ilişkisindedir.

Görünüm modeli oluşturma

Eğitmenler sayfasında üç farklı tablodan veriler gösterilir. Üç tabloyu temsil eden üç özellik içeren bir görünüm modeli gereklidir.

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

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace ContosoUniversity.Models.SchoolViewModels
{
    public class InstructorIndexData
    {
        public IEnumerable<Instructor> Instructors { get; set; }
        public IEnumerable<Course> Courses { get; set; }
        public IEnumerable<Enrollment> Enrollments { get; set; }
    }
}

yapı iskelesi Eğitmen sayfaları

Uygulamayı çalıştırın ve Eğitmenler sayfasına gidin.

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

using ContosoUniversity.Models;
using ContosoUniversity.Models.SchoolViewModels;  // Add VM
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.EntityFrameworkCore;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace ContosoUniversity.Pages.Instructors
{
    public class IndexModel : PageModel
    {
        private readonly ContosoUniversity.Data.SchoolContext _context;

        public IndexModel(ContosoUniversity.Data.SchoolContext context)
        {
            _context = context;
        }

        public InstructorIndexData InstructorData { get; set; }
        public int InstructorID { get; set; }
        public int CourseID { get; set; }

        public async Task OnGetAsync(int? id, int? courseID)
        {
            InstructorData = new InstructorIndexData();
            InstructorData.Instructors = await _context.Instructors
                .Include(i => i.OfficeAssignment)                 
                .Include(i => i.Courses)
                    .ThenInclude(c => c.Department)
                .OrderBy(i => i.LastName)
                .ToListAsync();

            if (id != null)
            {
                InstructorID = id.Value;
                Instructor instructor = InstructorData.Instructors
                    .Where(i => i.ID == id.Value).Single();
                InstructorData.Courses = instructor.Courses;
            }

            if (courseID != null)
            {
                CourseID = courseID.Value;
                IEnumerable<Enrollment> Enrollments = await _context.Enrollments
                    .Where(x => x.CourseID == CourseID)                    
                    .Include(i=>i.Student)
                    .ToListAsync();                 
                InstructorData.Enrollments = Enrollments;
            }
        }
    }
}

yöntemi, OnGetAsync seçilen eğitmenin kimliği için isteğe bağlı yol verilerini kabul eder.

Dosyadaki sorguyu Pages/Instructors/Index.cshtml.cs inceleyin:

InstructorData = new InstructorIndexData();
InstructorData.Instructors = await _context.Instructors
    .Include(i => i.OfficeAssignment)                 
    .Include(i => i.Courses)
        .ThenInclude(c => c.Department)
    .OrderBy(i => i.LastName)
    .ToListAsync();

Kod, aşağıdaki gezinti özellikleri için istekli yüklemeyi belirtir:

  • Instructor.OfficeAssignment
  • Instructor.Courses
    • Course.Department

Eğitmen seçildiğinde aşağıdaki kod yürütülür; yani id != null.

if (id != null)
{
    InstructorID = id.Value;
    Instructor instructor = InstructorData.Instructors
        .Where(i => i.ID == id.Value).Single();
    InstructorData.Courses = instructor.Courses;
}

Seçilen eğitmen, görünüm modelindeki eğitmenler listesinden alınır. Görünüm modelinin Courses özelliği, seçili eğitmenin CourseCourses gezinti özelliğindeki varlıklarla birlikte yüklenir.

Where yöntemi bir koleksiyon döndürür. Bu durumda, filtre tek bir varlık seçer, dolayısıyla Single koleksiyonu tek bir Instructor varlığa dönüştürmek için yöntemi çağrılır. Instructor Varlık, gezinti özelliğine Course erişim sağlar.

yöntemi Single , koleksiyonda yalnızca bir öğe olduğunda kullanılır. yöntemi, Single koleksiyon boşsa veya birden fazla öğe varsa bir özel durum oluşturur. Alternatif olarak SingleOrDefault, koleksiyon boşsa varsayılan bir değer döndürür. Bu sorgu için varsayılan null olarak döndürülür.

Aşağıdaki kod, bir kurs seçildiğinde görünüm modelinin Enrollments özelliğini doldurur:

if (courseID != null)
{
    CourseID = courseID.Value;
    IEnumerable<Enrollment> Enrollments = await _context.Enrollments
        .Where(x => x.CourseID == CourseID)                    
        .Include(i=>i.Student)
        .ToListAsync();                 
    InstructorData.Enrollments = Enrollments;
}

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

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

@page "{id:int?}"
@model ContosoUniversity.Pages.Instructors.IndexModel

@{
    ViewData["Title"] = "Instructors";
}

<h2>Instructors</h2>

<p>
    <a asp-page="Create">Create New</a>
</p>
<table class="table">
    <thead>
        <tr>
            <th>Last Name</th>
            <th>First Name</th>
            <th>Hire Date</th>
            <th>Office</th>
            <th>Courses</th>
            <th></th>
        </tr>
    </thead>
    <tbody>
        @foreach (var item in Model.InstructorData.Instructors)
        {
            string selectedRow = "";
            if (item.ID == Model.InstructorID)
            {
                selectedRow = "table-success";
            }
            <tr class="@selectedRow">
                <td>
                    @Html.DisplayFor(modelItem => item.LastName)
                </td>
                <td>
                    @Html.DisplayFor(modelItem => item.FirstMidName)
                </td>
                <td>
                    @Html.DisplayFor(modelItem => item.HireDate)
                </td>
                <td>
                    @if (item.OfficeAssignment != null)
                    {
                        @item.OfficeAssignment.Location
                    }
                </td>
                <td>
                    @{
                        foreach (var course in item.Courses)
                        {
                            @course.CourseID @:  @course.Title <br />
                        }
                    }
                </td>
                <td>
                    <a asp-page="./Index" asp-route-id="@item.ID">Select</a> |
                    <a asp-page="./Edit" asp-route-id="@item.ID">Edit</a> |
                    <a asp-page="./Details" asp-route-id="@item.ID">Details</a> |
                    <a asp-page="./Delete" asp-route-id="@item.ID">Delete</a>
                </td>
            </tr>
        }
    </tbody>
</table>

@if (Model.InstructorData.Courses != null)
{
    <h3>Courses Taught by Selected Instructor</h3>
    <table class="table">
        <tr>
            <th></th>
            <th>Number</th>
            <th>Title</th>
            <th>Department</th>
        </tr>

        @foreach (var item in Model.InstructorData.Courses)
        {
            string selectedRow = "";
            if (item.CourseID == Model.CourseID)
            {
                selectedRow = "table-success";
            }
            <tr class="@selectedRow">
                <td>
                    <a asp-page="./Index" asp-route-courseID="@item.CourseID">Select</a>
                </td>
                <td>
                    @item.CourseID
                </td>
                <td>
                    @item.Title
                </td>
                <td>
                    @item.Department.Name
                </td>
            </tr>
        }

    </table>
}

@if (Model.InstructorData.Enrollments != null)
{
    <h3>
        Students Enrolled in Selected Course
    </h3>
    <table class="table">
        <tr>
            <th>Name</th>
            <th>Grade</th>
        </tr>
        @foreach (var item in Model.InstructorData.Enrollments)
        {
            <tr>
                <td>
                    @item.Student.FullName
                </td>
                <td>
                    @Html.DisplayFor(modelItem => item.Grade)
                </td>
            </tr>
        }
    </table>
}

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

  • yönergesini page Güncelleştirmeler@page "{id:int?}". "{id:int?}" bir yol şablonudur. Yönlendirme şablonu, URL'deki tamsayı sorgu dizelerini verileri yönlendirmek için değiştirir. Örneğin, yalnızca yönergesi olan bir eğitmen için Seç bağlantısına tıklanması @page aşağıdakine benzer bir URL oluşturur:

    https://localhost:5001/Instructors?id=2

    Sayfa yönergesi olduğunda @page "{id:int?}"URL şöyledir: https://localhost:5001/Instructors/2

  • Yalnızca item.OfficeAssignment null değilse görüntülenen item.OfficeAssignment.Location bir Office sütunu ekler. Bu bire sıfıra veya bir ilişkisi olduğundan, ilgili bir OfficeAssignment varlığı olmayabilir.

    @if (item.OfficeAssignment != null)
    {
        @item.OfficeAssignment.Location
    }
    
  • Her eğitmen tarafından öğretilen kursları görüntüleyen bir Kurslar sütunu ekler. Bu razor söz dizimi hakkında daha fazla bilgi için bkz . Açık çizgi geçişi .

  • Seçili eğitmenin ve kursun tr öğesine dinamik olarak ekleyen class="table-success" kod ekler. Bu, Bootstrap sınıfını kullanarak seçili satır için bir arka plan rengi ayarlar.

    string selectedRow = "";
    if (item.CourseID == Model.CourseID)
    {
        selectedRow = "table-success";
    }
    <tr class="@selectedRow">
    
  • Seç etiketli yeni bir köprü ekler. Bu bağlantı, seçilen eğitmenin kimliğini yönteme Index gönderir ve bir arka plan rengi ayarlar.

    <a asp-action="Index" asp-route-id="@item.ID">Select</a> |
    
  • Seçili Eğitmen için bir kurs tablosu ekler.

  • Seçili kurs için bir öğrenci kayıtları tablosu ekler.

Uygulamayı çalıştırın ve Eğitmenler sekmesini seçin. Sayfada ilgili OfficeAssignment varlıktan Location (office) görüntülenir. Null ise OfficeAssignment , boş bir tablo hücresi görüntülenir.

Eğitmenin Seç bağlantısına tıklayın. Satır stili değişiklikleri ve bu eğitmene atanan kurslar görüntülenir.

Kayıtlı öğrencilerin listesini ve notlarını görmek için bir kurs seçin.

Instructors Index page instructor and course selected

Sonraki adımlar

Sonraki öğreticide ilgili verilerin nasıl güncelleştirilecekleri gösterilmektedir.

Bu öğreticide ilgili verilerin nasıl okunduğu ve görüntüleneceği gösterilmektedir. İlgili veriler, gezinti özelliklerine yüklenen verilerdir EF Core .

Aşağıdaki çizimlerde bu öğreticinin tamamlanmış sayfaları gösterilmektedir:

Courses Index page

Instructors Index page

İstekli, açık ve gecikmeli yükleme

Bir varlığın EF Core gezinti özelliklerine ilgili verileri yüklemenin birkaç yolu vardır:

  • İstekli yükleme. İstekli yükleme, bir varlık türüne yönelik bir sorgunun ilgili varlıkları da yüklediğinde gerçekleşir. Bir varlık okunduğunda ilgili verileri alınır. Bu genellikle gereken tüm verileri alan tek bir birleştirme sorgusuyla sonuçlanmıştır. EF Core bazı istekli yükleme türleri için birden çok sorgu yayımlar. Birden çok sorgu oluşturmak, dev bir tek sorgudan daha verimli olabilir. İstekli yükleme ve ThenInclude yöntemleriyle Include belirtilir.

    Eager loading example

    Bir koleksiyon gezintisi eklendiğinde, Eager yükleme birden çok sorgu gönderir:

    • Ana sorgu için bir sorgu
    • Yük ağacındaki her "edge" koleksiyonu için bir sorgu.
  • ile Loadayrı sorgular: Veriler ayrı sorgularda alınabilir ve EF Core gezinti özelliklerini "düzeltir". "Düzeltmeler", gezinti özelliklerini otomatik olarak dolduran EF Core anlamına gelir. ile Load ayrı sorgular, istekli yüklemeden çok açıkça yüklemeye benzer.

    Separate queries example

    Not:EF Core Daha önce bağlam örneğine yüklenmiş olan diğer varlıklara gezinti özelliklerini otomatik olarak düzeltir. Bir gezinti özelliğinin verileri açıkça dahil edilmese bile, ilgili varlıkların bazıları veya tümü önceden yüklenmişse özellik yine de doldurulabilir.

  • Açık yükleme. Varlık ilk kez okunduğunda ilgili veriler alınmaz. Gerekli olduğunda ilgili verileri almak için kod yazılmalıdır. Ayrı sorgularla açık yükleme, veritabanına birden çok sorgu gönderilmesine neden olur. Açık yükleme ile kod yüklenecek gezinti özelliklerini belirtir. Load Açık yükleme yapmak için yöntemini kullanın. Örnek:

    Explicit loading example

  • Yavaş yükleme. Varlık ilk kez okunduğunda ilgili veriler alınmaz. Bir gezinti özelliğine ilk kez erişildiğinde, bu gezinti özelliği için gereken veriler otomatik olarak alınır. Bir gezinti özelliğine ilk kez her erişildiğinde veritabanına bir sorgu gönderilir. Gecikmeli yükleme, örneğin geliştiriciler N+1 desenlerini kullandığında, üst öğe yükleyip alt öğeler arasında numaralandırıldığında performansı etkileyebilir.

Kurs sayfaları oluşturma

Varlık, Course ilgili Department varlığı içeren bir gezinti özelliği içerir.

Course.Department

Bir kurs için atanan bölümün adını görüntülemek için:

  • İlgili Department varlığı gezinti özelliğine Course.Department yükleyin.
  • Varlığın DepartmentName özelliğinden adı alın.

yapı iskelesi kursu sayfaları

  • Aşağıdaki özel durumlarla birlikte yapı iskelesi Öğrenci sayfalarındaki yönergeleri izleyin:

    • Sayfalar/Kurslar klasörü oluşturun.
    • Model sınıfı için kullanın Course .
    • Yeni bir tane oluşturmak yerine mevcut bağlam sınıfını kullanın.
  • yöntemini açın Pages/Courses/Index.cshtml.cs ve inceleyin OnGetAsync . yapı iskelesi altyapısı gezinti özelliği için istekli yükleme belirtti Department . Include yöntemi, istekli yüklemeyi belirtir.

  • Uygulamayı çalıştırın ve Kurslar bağlantısını seçin. Departman sütunu, kullanışlı olmayan öğesini görüntüler DepartmentID.

Bölüm adını görüntüleme

Pages/Courses/Index.cshtml.cs dosyasını aşağıdaki kodla güncelleştirin:

using ContosoUniversity.Models;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.EntityFrameworkCore;
using System.Collections.Generic;
using System.Threading.Tasks;

namespace ContosoUniversity.Pages.Courses
{
    public class IndexModel : PageModel
    {
        private readonly ContosoUniversity.Data.SchoolContext _context;

        public IndexModel(ContosoUniversity.Data.SchoolContext context)
        {
            _context = context;
        }

        public IList<Course> Courses { get; set; }

        public async Task OnGetAsync()
        {
            Courses = await _context.Courses
                .Include(c => c.Department)
                .AsNoTracking()
                .ToListAsync();
        }
    }
}

Yukarıdaki kod özelliğini olarak Courses değiştirir Course ve eklerAsNoTracking. AsNoTracking döndürülen varlıklar izlenmediği için performansı artırır. Varlıkların geçerli bağlamda güncelleştirilmediğinden izlenmesi gerekmez.

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

@page
@model ContosoUniversity.Pages.Courses.IndexModel

@{
    ViewData["Title"] = "Courses";
}

<h1>Courses</h1>

<p>
    <a asp-page="Create">Create New</a>
</p>
<table class="table">
    <thead>
        <tr>
            <th>
                @Html.DisplayNameFor(model => model.Courses[0].CourseID)
            </th>
            <th>
                @Html.DisplayNameFor(model => model.Courses[0].Title)
            </th>
            <th>
                @Html.DisplayNameFor(model => model.Courses[0].Credits)
            </th>
            <th>
                @Html.DisplayNameFor(model => model.Courses[0].Department)
            </th>
            <th></th>
        </tr>
    </thead>
    <tbody>
@foreach (var item in Model.Courses)
{
        <tr>
            <td>
                @Html.DisplayFor(modelItem => item.CourseID)
            </td>
            <td>
                @Html.DisplayFor(modelItem => item.Title)
            </td>
            <td>
                @Html.DisplayFor(modelItem => item.Credits)
            </td>
            <td>
                @Html.DisplayFor(modelItem => item.Department.Name)
            </td>
            <td>
                <a asp-page="./Edit" asp-route-id="@item.CourseID">Edit</a> |
                <a asp-page="./Details" asp-route-id="@item.CourseID">Details</a> |
                <a asp-page="./Delete" asp-route-id="@item.CourseID">Delete</a>
            </td>
        </tr>
}
    </tbody>
</table>

yapı iskelesi oluşturulmuş kodda aşağıdaki değişiklikler yapılmıştır:

  • Course Özellik adı olarak Coursesdeğiştirildi.

  • Özellik değerini gösteren CourseID bir Sayı sütunu eklendi. Varsayılan olarak, birincil anahtarlar son kullanıcılar için anlamlı olmadığından yapı iskelesi oluşturmaz. Ancak, bu durumda birincil anahtar anlamlıdır.

  • Departman adını görüntülemek için Department sütunu değiştirildi. Kod, gezinti özelliğine Department yüklenen varlığın Department özelliğini görüntülerName:

    @Html.DisplayFor(modelItem => item.Department.Name)
    

Uygulamayı çalıştırın ve bölüm adlarını içeren listeyi görmek için Kurslar sekmesini seçin.

Courses Index page

yöntemi, OnGetAsync yöntemiyle Include ilgili verileri yükler. Select yöntemi, yalnızca gerekli olan ilgili verileri yükleyen bir alternatiftir. Gibi tek öğeler için Department.Name SQL INNER JOIN kullanır. Koleksiyonlar için başka bir veritabanı erişimi kullanır, ancak koleksiyonlardaki Include işleci de kullanır.

Aşağıdaki kod yöntemiyle Select ilgili verileri yükler:

public IList<CourseViewModel> CourseVM { get; set; }

public async Task OnGetAsync()
{
    CourseVM = await _context.Courses
            .Select(p => new CourseViewModel
            {
                CourseID = p.CourseID,
                Title = p.Title,
                Credits = p.Credits,
                DepartmentName = p.Department.Name
            }).ToListAsync();
}

Yukarıdaki kod herhangi bir varlık türü döndürmez, bu nedenle izleme yapılmaz. EF izleme hakkında daha fazla bilgi için bkz . İzleme ve İzleme Olmayan Sorgular.

:CourseViewModel

public class CourseViewModel
{
    public int CourseID { get; set; }
    public string Title { get; set; }
    public int Credits { get; set; }
    public string DepartmentName { get; set; }
}

Tam bir örnek için bkz . IndexSelect.cshtml ve IndexSelect.cshtml.cs .

Eğitmen sayfaları oluşturma

Bu bölüm, Eğitmen sayfalarının iskelesini oluşturur ve eğitmen dizini sayfasına ilgili Kurslar ve Kayıtlar ekler.

Instructors Index page

Bu sayfa, ilgili verileri aşağıdaki yollarla okur ve görüntüler:

  • Eğitmen listesi, varlıktan OfficeAssignment (önceki görüntüde Office) ilgili verileri görüntüler. Instructor ve OfficeAssignment varlıkları bire sıfıra veya bir ilişkisindedir. Varlıklar için OfficeAssignment istekli yükleme kullanılır. İstekli yükleme genellikle ilgili verilerin görüntülenmesi gerektiğinde daha verimli olur. Bu durumda, eğitmenler için ofis ödevleri görüntülenir.
  • Kullanıcı bir eğitmen seçtiğinde ilgili Course varlıklar görüntülenir. Instructor ve Course varlıkları çoka çok ilişkisindedir. Hevesle yükleme, varlıklar ve ilgili Department varlıkları için Course kullanılır. Bu durumda, yalnızca seçilen eğitmene yönelik kurslar gerektiğinden ayrı sorgular daha verimli olabilir. Bu örnekte, gezinti özelliklerindeki varlıklarda gezinti özellikleri için istekli yüklemenin nasıl kullanılacağı gösterilmektedir.
  • Kullanıcı bir kurs seçtiğinde, varlıktan Enrollments ilgili veriler görüntülenir. Önceki resimde öğrenci adı ve notu görüntülenir. Course ve Enrollment varlıkları bire çok ilişkisindedir.

Görünüm modeli oluşturma

Eğitmenler sayfasında üç farklı tablodan veriler gösterilir. Üç tabloyu temsil eden üç özellik içeren bir görünüm modeli gereklidir.

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

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace ContosoUniversity.Models.SchoolViewModels
{
    public class InstructorIndexData
    {
        public IEnumerable<Instructor> Instructors { get; set; }
        public IEnumerable<Course> Courses { get; set; }
        public IEnumerable<Enrollment> Enrollments { get; set; }
    }
}

yapı iskelesi Eğitmen sayfaları

İskeleli sayfanın güncelleştirmeden önce nasıl göründüğünü görmek için uygulamayı çalıştırın ve Eğitmenler sayfasına gidin.

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

using ContosoUniversity.Models;
using ContosoUniversity.Models.SchoolViewModels;  // Add VM
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.EntityFrameworkCore;
using System.Linq;
using System.Threading.Tasks;

namespace ContosoUniversity.Pages.Instructors
{
    public class IndexModel : PageModel
    {
        private readonly ContosoUniversity.Data.SchoolContext _context;

        public IndexModel(ContosoUniversity.Data.SchoolContext context)
        {
            _context = context;
        }

        public InstructorIndexData InstructorData { get; set; }
        public int InstructorID { get; set; }
        public int CourseID { get; set; }

        public async Task OnGetAsync(int? id, int? courseID)
        {
            InstructorData = new InstructorIndexData();
            InstructorData.Instructors = await _context.Instructors
                .Include(i => i.OfficeAssignment)                 
                .Include(i => i.CourseAssignments)
                    .ThenInclude(i => i.Course)
                        .ThenInclude(i => i.Department)
                .Include(i => i.CourseAssignments)
                    .ThenInclude(i => i.Course)
                        .ThenInclude(i => i.Enrollments)
                            .ThenInclude(i => i.Student)
                .AsNoTracking()
                .OrderBy(i => i.LastName)
                .ToListAsync();

            if (id != null)
            {
                InstructorID = id.Value;
                Instructor instructor = InstructorData.Instructors
                    .Where(i => i.ID == id.Value).Single();
                InstructorData.Courses = instructor.CourseAssignments.Select(s => s.Course);
            }

            if (courseID != null)
            {
                CourseID = courseID.Value;
                var selectedCourse = InstructorData.Courses
                    .Where(x => x.CourseID == courseID).Single();
                InstructorData.Enrollments = selectedCourse.Enrollments;
            }
        }
    }
}

yöntemi, OnGetAsync seçilen eğitmenin kimliği için isteğe bağlı yol verilerini kabul eder.

Dosyadaki sorguyu Pages/Instructors/Index.cshtml.cs inceleyin:

InstructorData.Instructors = await _context.Instructors
    .Include(i => i.OfficeAssignment)                 
    .Include(i => i.CourseAssignments)
        .ThenInclude(i => i.Course)
            .ThenInclude(i => i.Department)
    .Include(i => i.CourseAssignments)
        .ThenInclude(i => i.Course)
            .ThenInclude(i => i.Enrollments)
                .ThenInclude(i => i.Student)
    .AsNoTracking()
    .OrderBy(i => i.LastName)
    .ToListAsync();

Kod, aşağıdaki gezinti özellikleri için istekli yüklemeyi belirtir:

  • Instructor.OfficeAssignment
  • Instructor.CourseAssignments
    • CourseAssignments.Course
      • Course.Department
      • Course.Enrollments
        • Enrollment.Student

ve Courseiçin ve ThenInclude yöntemlerinin yinelenmesine IncludeCourseAssignments dikkat edin. Varlığın iki gezinti özelliği Course için hevesle yüklemeyi belirtmek için bu yineleme gereklidir.

Bir eğitmen seçildiğinde (id != null aşağıdaki kod yürütülür.

if (id != null)
{
    InstructorID = id.Value;
    Instructor instructor = InstructorData.Instructors
        .Where(i => i.ID == id.Value).Single();
    InstructorData.Courses = instructor.CourseAssignments.Select(s => s.Course);
}

Seçilen eğitmen, görünüm modelindeki eğitmenler listesinden alınır. Görünüm modelinin Courses özelliği, eğitmenin CourseCourseAssignments gezinti özelliğindeki varlıklarla birlikte yüklenir.

Where yöntemi bir koleksiyon döndürür. Ancak bu durumda, filtre tek bir varlık seçer, bu nedenle Single koleksiyonu tek Instructor bir varlığa dönüştürmek için yöntemi çağrılır. varlık Instructor özelliğine CourseAssignments erişim sağlar. CourseAssignments ilgili Course varlıklara erişim sağlar.

Instructor-to-Courses m:M

yöntemi Single , koleksiyonda yalnızca bir öğe olduğunda kullanılır. yöntemi, Single koleksiyon boşsa veya birden fazla öğe varsa bir özel durum oluşturur. Alternatif olarak SingleOrDefault, koleksiyon boşsa varsayılan bir değer (bu örnekte null) döndürür.

Aşağıdaki kod, bir kurs seçildiğinde görünüm modelinin Enrollments özelliğini doldurur:

if (courseID != null)
{
    CourseID = courseID.Value;
    var selectedCourse = InstructorData.Courses
        .Where(x => x.CourseID == courseID).Single();
    InstructorData.Enrollments = selectedCourse.Enrollments;
}

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

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

@page "{id:int?}"
@model ContosoUniversity.Pages.Instructors.IndexModel

@{
    ViewData["Title"] = "Instructors";
}

<h2>Instructors</h2>

<p>
    <a asp-page="Create">Create New</a>
</p>
<table class="table">
    <thead>
        <tr>
            <th>Last Name</th>
            <th>First Name</th>
            <th>Hire Date</th>
            <th>Office</th>
            <th>Courses</th>
            <th></th>
        </tr>
    </thead>
    <tbody>
        @foreach (var item in Model.InstructorData.Instructors)
        {
            string selectedRow = "";
            if (item.ID == Model.InstructorID)
            {
                selectedRow = "table-success";
            }
            <tr class="@selectedRow">
                <td>
                    @Html.DisplayFor(modelItem => item.LastName)
                </td>
                <td>
                    @Html.DisplayFor(modelItem => item.FirstMidName)
                </td>
                <td>
                    @Html.DisplayFor(modelItem => item.HireDate)
                </td>
                <td>
                    @if (item.OfficeAssignment != null)
                    {
                        @item.OfficeAssignment.Location
                    }
                </td>
                <td>
                    @{
                        foreach (var course in item.CourseAssignments)
                        {
                            @course.Course.CourseID @:  @course.Course.Title <br />
                        }
                    }
                </td>
                <td>
                    <a asp-page="./Index" asp-route-id="@item.ID">Select</a> |
                    <a asp-page="./Edit" asp-route-id="@item.ID">Edit</a> |
                    <a asp-page="./Details" asp-route-id="@item.ID">Details</a> |
                    <a asp-page="./Delete" asp-route-id="@item.ID">Delete</a>
                </td>
            </tr>
        }
    </tbody>
</table>

@if (Model.InstructorData.Courses != null)
{
    <h3>Courses Taught by Selected Instructor</h3>
    <table class="table">
        <tr>
            <th></th>
            <th>Number</th>
            <th>Title</th>
            <th>Department</th>
        </tr>

        @foreach (var item in Model.InstructorData.Courses)
        {
            string selectedRow = "";
            if (item.CourseID == Model.CourseID)
            {
                selectedRow = "table-success";
            }
            <tr class="@selectedRow">
                <td>
                    <a asp-page="./Index" asp-route-courseID="@item.CourseID">Select</a>
                </td>
                <td>
                    @item.CourseID
                </td>
                <td>
                    @item.Title
                </td>
                <td>
                    @item.Department.Name
                </td>
            </tr>
        }

    </table>
}

@if (Model.InstructorData.Enrollments != null)
{
    <h3>
        Students Enrolled in Selected Course
    </h3>
    <table class="table">
        <tr>
            <th>Name</th>
            <th>Grade</th>
        </tr>
        @foreach (var item in Model.InstructorData.Enrollments)
        {
            <tr>
                <td>
                    @item.Student.FullName
                </td>
                <td>
                    @Html.DisplayFor(modelItem => item.Grade)
                </td>
            </tr>
        }
    </table>
}

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

  • yönergesini page ile @page@page "{id:int?}"Güncelleştirmeler. "{id:int?}" bir yol şablonudur. Yönlendirme şablonu, URL'deki tamsayı sorgu dizelerini verileri yönlendirmek için değiştirir. Örneğin, yalnızca yönergesi olan bir eğitmen için Seç bağlantısına tıklanması @page aşağıdakine benzer bir URL oluşturur:

    https://localhost:5001/Instructors?id=2

    Sayfa yönergesi olduğunda @page "{id:int?}"URL şöyledir:

    https://localhost:5001/Instructors/2

  • Yalnızca item.OfficeAssignment null değilse görüntülenen item.OfficeAssignment.Location bir Office sütunu ekler. Bu bire sıfıra veya bir ilişkisi olduğundan, ilgili bir OfficeAssignment varlığı olmayabilir.

    @if (item.OfficeAssignment != null)
    {
        @item.OfficeAssignment.Location
    }
    
  • Her eğitmen tarafından öğretilen kursları görüntüleyen bir Kurslar sütunu ekler. Bu razor söz dizimi hakkında daha fazla bilgi için bkz . Açık çizgi geçişi .

  • Seçili eğitmenin ve kursun tr öğesine dinamik olarak ekleyen class="table-success" kod ekler. Bu, Bootstrap sınıfını kullanarak seçili satır için bir arka plan rengi ayarlar.

    string selectedRow = "";
    if (item.CourseID == Model.CourseID)
    {
        selectedRow = "table-success";
    }
    <tr class="@selectedRow">
    
  • Seç etiketli yeni bir köprü ekler. Bu bağlantı, seçilen eğitmenin kimliğini yönteme Index gönderir ve bir arka plan rengi ayarlar.

    <a asp-action="Index" asp-route-id="@item.ID">Select</a> |
    
  • Seçili Eğitmen için bir kurs tablosu ekler.

  • Seçili kurs için bir öğrenci kayıtları tablosu ekler.

Uygulamayı çalıştırın ve Eğitmenler sekmesini seçin. Sayfada ilgili OfficeAssignment varlıktan Location (office) görüntülenir. Null ise OfficeAssignment , boş bir tablo hücresi görüntülenir.

Eğitmenin Seç bağlantısına tıklayın. Satır stili değişiklikleri ve bu eğitmene atanan kurslar görüntülenir.

Kayıtlı öğrencilerin listesini ve notlarını görmek için bir kurs seçin.

Instructors Index page instructor and course selected

TekLi Kullanma

yöntemi, Single yöntemi ayrı olarak çağırmak yerine koşulunu Where geçirebilirWhere:

public async Task OnGetAsync(int? id, int? courseID)
{
    InstructorData = new InstructorIndexData();

    InstructorData.Instructors = await _context.Instructors
          .Include(i => i.OfficeAssignment)
          .Include(i => i.CourseAssignments)
            .ThenInclude(i => i.Course)
                .ThenInclude(i => i.Department)
            .Include(i => i.CourseAssignments)
                .ThenInclude(i => i.Course)
                    .ThenInclude(i => i.Enrollments)
                        .ThenInclude(i => i.Student)
          .AsNoTracking()
          .OrderBy(i => i.LastName)
          .ToListAsync();

    if (id != null)
    {
        InstructorID = id.Value;
        Instructor instructor = InstructorData.Instructors.Single(
            i => i.ID == id.Value);
        InstructorData.Courses = instructor.CourseAssignments.Select(
            s => s.Course);
    }

    if (courseID != null)
    {
        CourseID = courseID.Value;
        InstructorData.Enrollments = InstructorData.Courses.Single(
            x => x.CourseID == courseID).Enrollments;
    }
}

Single Where koşuluyla kullanımı kişisel tercih meselesidir. Yöntemini kullanmanın Where hiçbir avantajı yoktur.

Belirtik yükleme

Geçerli kod ve Studentsiçin Enrollments istekli yüklemeyi belirtir:

InstructorData.Instructors = await _context.Instructors
    .Include(i => i.OfficeAssignment)                 
    .Include(i => i.CourseAssignments)
        .ThenInclude(i => i.Course)
            .ThenInclude(i => i.Department)
    .Include(i => i.CourseAssignments)
        .ThenInclude(i => i.Course)
            .ThenInclude(i => i.Enrollments)
                .ThenInclude(i => i.Student)
    .AsNoTracking()
    .OrderBy(i => i.LastName)
    .ToListAsync();

Kullanıcıların kurstaki kayıtları nadiren görmek istediğini varsayalım. Bu durumda en iyi duruma getirme yalnızca istenen kayıt verilerini yüklemektir. Bu bölümde, OnGetAsync ve Studentsaçık yüklemesini Enrollments kullanacak şekilde güncelleştirilir.

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

using ContosoUniversity.Models;
using ContosoUniversity.Models.SchoolViewModels;  // Add VM
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.EntityFrameworkCore;
using System.Linq;
using System.Threading.Tasks;

namespace ContosoUniversity.Pages.Instructors
{
    public class IndexModel : PageModel
    {
        private readonly ContosoUniversity.Data.SchoolContext _context;

        public IndexModel(ContosoUniversity.Data.SchoolContext context)
        {
            _context = context;
        }

        public InstructorIndexData InstructorData { get; set; }
        public int InstructorID { get; set; }
        public int CourseID { get; set; }

        public async Task OnGetAsync(int? id, int? courseID)
        {
            InstructorData = new InstructorIndexData();
            InstructorData.Instructors = await _context.Instructors
                .Include(i => i.OfficeAssignment)                 
                .Include(i => i.CourseAssignments)
                    .ThenInclude(i => i.Course)
                        .ThenInclude(i => i.Department)
                //.Include(i => i.CourseAssignments)
                //    .ThenInclude(i => i.Course)
                //        .ThenInclude(i => i.Enrollments)
                //            .ThenInclude(i => i.Student)
                //.AsNoTracking()
                .OrderBy(i => i.LastName)
                .ToListAsync();

            if (id != null)
            {
                InstructorID = id.Value;
                Instructor instructor = InstructorData.Instructors
                    .Where(i => i.ID == id.Value).Single();
                InstructorData.Courses = instructor.CourseAssignments.Select(s => s.Course);
            }

            if (courseID != null)
            {
                CourseID = courseID.Value;
                var selectedCourse = InstructorData.Courses
                    .Where(x => x.CourseID == courseID).Single();
                await _context.Entry(selectedCourse).Collection(x => x.Enrollments).LoadAsync();
                foreach (Enrollment enrollment in selectedCourse.Enrollments)
                {
                    await _context.Entry(enrollment).Reference(x => x.Student).LoadAsync();
                }
                InstructorData.Enrollments = selectedCourse.Enrollments;
            }
        }
    }
}

Yukarıdaki kod, kayıt ve öğrenci verileri için ThenInclude yöntemi çağrılarını bırakır. Bir kurs seçilirse, açık yükleme kodu şunları alır:

  • Enrollment Seçili kursun varlıkları.
  • Student Her Enrollmentiçin varlıklar.

Yukarıdaki kodun açıklamasının .AsNoTracking()olduğuna dikkat edin. Gezinti özellikleri yalnızca izlenen varlıklar için açıkça yüklenebilir.

Uygulamayı test etme. Kullanıcı açısından bakıldığında, uygulama önceki sürümle aynı şekilde davranır.

Sonraki adımlar

Sonraki öğreticide ilgili verilerin nasıl güncelleştirilecekleri gösterilmektedir.

Bu öğreticide, ilgili veriler okunur ve görüntülenir. İlgili veriler, gezinti özelliklerine yüklenen verilerdir EF Core .

Çözemediğiniz sorunlarla karşılaşırsanız tamamlanmış uygulamayı indirin veya görüntüleyin.İndirme yönergeleri.

Aşağıdaki çizimlerde bu öğreticinin tamamlanmış sayfaları gösterilmektedir:

Courses Index page

Instructors Index page

Bir varlığın EF Core gezinti özelliklerine ilgili verileri yüklemenin birkaç yolu vardır:

  • İstekli yükleme. İstekli yükleme, bir varlık türüne yönelik bir sorgunun ilgili varlıkları da yüklediğinde gerçekleşir. Varlık okunduğunda ilgili verileri alınır. Bu genellikle gereken tüm verileri alan tek bir birleştirme sorgusuyla sonuçlanmıştır. EF Core bazı istekli yükleme türleri için birden çok sorgu yayımlar. Birden çok sorgunun verilmesi, EF6'da tek bir sorgunun bulunduğu bazı sorgular için geçerli olandan daha verimli olabilir. İstekli yükleme ve ThenInclude yöntemleriyle Include belirtilir.

    Eager loading example

    Bir koleksiyon gezintisi eklendiğinde, Eager yükleme birden çok sorgu gönderir:

    • Ana sorgu için bir sorgu
    • Yük ağacındaki her "edge" koleksiyonu için bir sorgu.
  • ile Loadayrı sorgular: Veriler ayrı sorgularda alınabilir ve EF Core gezinti özelliklerini "düzeltir". "düzeltmeler", gezinti özelliklerini otomatik olarak dolduran EF Core anlamına gelir. ile Load ayrı sorgular, istekli yüklemeden çok açıkça yüklemeye benzer.

    Separate queries example

    Not: EF Core Daha önce bağlam örneğine yüklenmiş olan diğer varlıklara gezinti özelliklerini otomatik olarak düzeltir. Bir gezinti özelliğinin verileri açıkça dahil edilmese bile, ilgili varlıkların bazıları veya tümü önceden yüklenmişse özellik yine de doldurulabilir.

  • Açık yükleme. Varlık ilk kez okunduğunda ilgili veriler alınmaz. Gerekli olduğunda ilgili verileri almak için kod yazılmalıdır. Ayrı sorgularla açık yükleme, db'ye gönderilen birden çok sorguyla sonuçılır. Açık yükleme ile kod yüklenecek gezinti özelliklerini belirtir. Load Açık yükleme yapmak için yöntemini kullanın. Örnek:

    Explicit loading example

  • Yavaş yükleme. Sürüm 2.1'de EF Coregecikmeli yükleme eklendi. Varlık ilk kez okunduğunda ilgili veriler alınmaz. Bir gezinti özelliğine ilk kez erişildiğinde, bu gezinti özelliği için gereken veriler otomatik olarak alınır. Bir gezinti özelliğine ilk kez her erişildiğinde db'ye bir sorgu gönderilir.

  • İşleç Select yalnızca gerekli olan ilgili verileri yükler.

Bölüm adını görüntüleyen bir Kurs sayfası oluşturma

Course varlığı, varlığı içeren bir gezinti özelliği içerir Department . Varlık, Department kursun atandığı bölümü içerir.

Atanan bölümün adını bir kurs listesinde görüntülemek için:

  • Name Varlığından Department özelliğini alın.
  • Varlık Department gezinti özelliğinden Course.Department gelir.

Course.Department

Kurs modelinin iskelesini oluşturma

Öğrenci modelinin iskelesini oluşturma ve model sınıfı için kullanma Course başlığı altında yer alan yönergeleri izleyin.

Yukarıdaki komut modelin iskelesini Course oluşturur. Projeyi Visual Studio'da açın.

yöntemini açın Pages/Courses/Index.cshtml.cs ve inceleyin OnGetAsync . yapı iskelesi altyapısı gezinti özelliği için istekli yükleme belirtti Department . Include yöntemi, istekli yüklemeyi belirtir.

Uygulamayı çalıştırın ve Kurslar bağlantısını seçin. Departman sütunu, kullanışlı olmayan öğesini görüntüler DepartmentID.

OnGetAsync yöntemini aşağıdaki kodla güncelleştirin:

public async Task OnGetAsync()
{
    Course = await _context.Courses
        .Include(c => c.Department)
        .AsNoTracking()
        .ToListAsync();
}

Yukarıdaki kod ekler AsNoTracking. AsNoTracking döndürülen varlıklar izlenmediği için performansı artırır. Varlıklar geçerli bağlamda güncelleştirilmediğinden izlenmez.

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

@page
@model ContosoUniversity.Pages.Courses.IndexModel
@{
    ViewData["Title"] = "Courses";
}

<h2>Courses</h2>

<p>
    <a asp-page="Create">Create New</a>
</p>
<table class="table">
    <thead>
        <tr>
            <th>
                @Html.DisplayNameFor(model => model.Course[0].CourseID)
            </th>
            <th>
                @Html.DisplayNameFor(model => model.Course[0].Title)
            </th>
            <th>
                @Html.DisplayNameFor(model => model.Course[0].Credits)
            </th>
            <th>
                @Html.DisplayNameFor(model => model.Course[0].Department)
            </th>
            <th></th>
        </tr>
    </thead>
    <tbody>
        @foreach (var item in Model.Course)
        {
            <tr>
                <td>
                    @Html.DisplayFor(modelItem => item.CourseID)
                </td>
                <td>
                    @Html.DisplayFor(modelItem => item.Title)
                </td>
                <td>
                    @Html.DisplayFor(modelItem => item.Credits)
                </td>
                <td>
                    @Html.DisplayFor(modelItem => item.Department.Name)
                </td>
                <td>
                    <a asp-page="./Edit" asp-route-id="@item.CourseID">Edit</a> |
                    <a asp-page="./Details" asp-route-id="@item.CourseID">Details</a> |
                    <a asp-page="./Delete" asp-route-id="@item.CourseID">Delete</a>
                </td>
            </tr>
        }
    </tbody>
</table>

yapı iskelesi oluşturulmuş kodda aşağıdaki değişiklikler yapılmıştır:

  • Dizin başlığı Kurslar olarak değiştirildi.

  • Özellik değerini gösteren CourseID bir Sayı sütunu eklendi. Varsayılan olarak, birincil anahtarlar son kullanıcılar için anlamlı olmadığından yapı iskelesi oluşturmaz. Ancak, bu durumda birincil anahtar anlamlıdır.

  • Departman adını görüntülemek için Department sütunu değiştirildi. Kod, gezinti özelliğine Department yüklenen varlığın Department özelliğini görüntülerName:

    @Html.DisplayFor(modelItem => item.Department.Name)
    

Uygulamayı çalıştırın ve bölüm adlarını içeren listeyi görmek için Kurslar sekmesini seçin.

Courses Index page

yöntemi, OnGetAsync aşağıdaki yöntemle Include ilgili verileri yükler:

public async Task OnGetAsync()
{
    Course = await _context.Courses
        .Include(c => c.Department)
        .AsNoTracking()
        .ToListAsync();
}

İşleç Select yalnızca gerekli olan ilgili verileri yükler. Gibi tek öğeler için Department.Name SQL INNER JOIN kullanır. Koleksiyonlar için başka bir veritabanı erişimi kullanır, ancak koleksiyonlardaki Include işleci de kullanır.

Aşağıdaki kod yöntemiyle Select ilgili verileri yükler:

public IList<CourseViewModel> CourseVM { get; set; }

public async Task OnGetAsync()
{
    CourseVM = await _context.Courses
            .Select(p => new CourseViewModel
            {
                CourseID = p.CourseID,
                Title = p.Title,
                Credits = p.Credits,
                DepartmentName = p.Department.Name
            }).ToListAsync();
}

:CourseViewModel

public class CourseViewModel
{
    public int CourseID { get; set; }
    public string Title { get; set; }
    public int Credits { get; set; }
    public string DepartmentName { get; set; }
}

Tam bir örnek için bkz . IndexSelect.cshtml ve IndexSelect.cshtml.cs .

Kurslar ve Kayıtları gösteren eğitmenler sayfası oluşturma

Bu bölümde Eğitmenler sayfası oluşturulur.

Instructors Index page

Bu sayfa, ilgili verileri aşağıdaki yollarla okur ve görüntüler:

  • Eğitmen listesi, varlıktan OfficeAssignment (önceki görüntüde Office) ilgili verileri görüntüler. Instructor ve OfficeAssignment varlıkları bire sıfıra veya bir ilişkisindedir. Varlıklar için OfficeAssignment istekli yükleme kullanılır. İstekli yükleme genellikle ilgili verilerin görüntülenmesi gerektiğinde daha verimli olur. Bu durumda, eğitmenler için ofis ödevleri görüntülenir.
  • Kullanıcı bir eğitmen seçtiğinde (önceki görüntüde Harui), ilgili Course varlıklar görüntülenir. Instructor ve Course varlıkları çoka çok ilişkisindedir. Hevesle yükleme, varlıklar ve ilgili Department varlıkları için Course kullanılır. Bu durumda, yalnızca seçilen eğitmene yönelik kurslar gerektiğinden ayrı sorgular daha verimli olabilir. Bu örnekte, gezinti özelliklerindeki varlıklarda gezinti özellikleri için istekli yüklemenin nasıl kullanılacağı gösterilmektedir.
  • Kullanıcı bir kurs seçtiğinde (önceki görüntüde kimya), varlıktan Enrollments ilgili veriler görüntülenir. Önceki resimde öğrenci adı ve notu görüntülenir. Course ve Enrollment varlıkları bire çok ilişkisindedir.

Eğitmen Dizini görünümü için görünüm modeli oluşturma

Eğitmenler sayfasında üç farklı tablodan veriler gösterilir. Üç tabloyu temsil eden üç varlığı içeren bir görünüm modeli oluşturulur.

SchoolViewModels klasöründe aşağıdaki kodla oluşturunInstructorIndexData.cs:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace ContosoUniversity.Models.SchoolViewModels
{
    public class InstructorIndexData
    {
        public IEnumerable<Instructor> Instructors { get; set; }
        public IEnumerable<Course> Courses { get; set; }
        public IEnumerable<Enrollment> Enrollments { get; set; }
    }
}

Eğitmen modelinin iskelesini oluşturma

Öğrenci modelinin iskelesini oluşturma ve model sınıfı için kullanma Instructor başlığı altında yer alan yönergeleri izleyin.

Yukarıdaki komut modelin iskelesini Instructor oluşturur. Uygulamayı çalıştırın ve eğitmenler sayfasına gidin.

değerini aşağıdaki kodla değiştirin Pages/Instructors/Index.cshtml.cs :

using ContosoUniversity.Models;
using ContosoUniversity.Models.SchoolViewModels;  // Add VM
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.EntityFrameworkCore;
using System.Linq;
using System.Threading.Tasks;

namespace ContosoUniversity.Pages.Instructors
{
    public class IndexModel : PageModel
    {
        private readonly ContosoUniversity.Data.SchoolContext _context;

        public IndexModel(ContosoUniversity.Data.SchoolContext context)
        {
            _context = context;
        }

        public InstructorIndexData Instructor { get; set; }
        public int InstructorID { get; set; }

        public async Task OnGetAsync(int? id)
        {
            Instructor = new InstructorIndexData();
            Instructor.Instructors = await _context.Instructors
                  .Include(i => i.OfficeAssignment)
                  .Include(i => i.CourseAssignments)
                    .ThenInclude(i => i.Course)
                  .AsNoTracking()
                  .OrderBy(i => i.LastName)
                  .ToListAsync();

            if (id != null)
            {
                InstructorID = id.Value;
            }           
        }
    }
}

yöntemi, OnGetAsync seçilen eğitmenin kimliği için isteğe bağlı yol verilerini kabul eder.

Dosyadaki sorguyu Pages/Instructors/Index.cshtml.cs inceleyin:

Instructor.Instructors = await _context.Instructors
      .Include(i => i.OfficeAssignment)
      .Include(i => i.CourseAssignments)
        .ThenInclude(i => i.Course)
      .AsNoTracking()
      .OrderBy(i => i.LastName)
      .ToListAsync();

Sorgunun iki tane vardır:

  • OfficeAssignment: Eğitmenler görünümünde görüntülenir.
  • CourseAssignments: Bu da öğretilen dersleri getirir.

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

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

@page "{id:int?}"
@model ContosoUniversity.Pages.Instructors.IndexModel

@{
    ViewData["Title"] = "Instructors";
}

<h2>Instructors</h2>

<p>
    <a asp-page="Create">Create New</a>
</p>
<table class="table">
    <thead>
        <tr>
            <th>Last Name</th>
            <th>First Name</th>
            <th>Hire Date</th>
            <th>Office</th>
            <th>Courses</th>
            <th></th>
        </tr>
    </thead>
    <tbody>
        @foreach (var item in Model.Instructor.Instructors)
        {
            string selectedRow = "";
            if (item.ID == Model.InstructorID)
            {
                selectedRow = "success";
            }
            <tr class="@selectedRow">
                <td>
                    @Html.DisplayFor(modelItem => item.LastName)
                </td>
                <td>
                    @Html.DisplayFor(modelItem => item.FirstMidName)
                </td>
                <td>
                    @Html.DisplayFor(modelItem => item.HireDate)
                </td>
                <td>
                    @if (item.OfficeAssignment != null)
                    {
                        @item.OfficeAssignment.Location
                    }
                </td>
                <td>
                    @{
                        foreach (var course in item.CourseAssignments)
                        {
                            @course.Course.CourseID @:  @course.Course.Title <br />
                        }
                    }
                </td>
                <td>
                    <a asp-page="./Index" asp-route-id="@item.ID">Select</a> |
                    <a asp-page="./Edit" asp-route-id="@item.ID">Edit</a> |
                    <a asp-page="./Details" asp-route-id="@item.ID">Details</a> |
                    <a asp-page="./Delete" asp-route-id="@item.ID">Delete</a>
                </td>
            </tr>
        }
    </tbody>
</table>

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

  • yönergesini page ile @page@page "{id:int?}"Güncelleştirmeler. "{id:int?}" bir yol şablonudur. Yönlendirme şablonu, URL'deki tamsayı sorgu dizelerini verileri yönlendirmek için değiştirir. Örneğin, yalnızca yönergesi olan bir eğitmen için Seç bağlantısına tıklanması @page aşağıdakine benzer bir URL oluşturur:

    http://localhost:1234/Instructors?id=2

    Sayfa yönergesi olduğunda @page "{id:int?}", önceki URL şöyledir:

    http://localhost:1234/Instructors/2

  • Sayfa başlığı Eğitmenler'dir.

  • Yalnızca item.OfficeAssignment null değilse görüntülenen item.OfficeAssignment.Location bir Office sütunu eklendi. Bu bire sıfıra veya bir ilişkisi olduğundan, ilgili bir OfficeAssignment varlığı olmayabilir.

    @if (item.OfficeAssignment != null)
    {
        @item.OfficeAssignment.Location
    }
    
  • Her eğitmen tarafından öğretilen kursları görüntüleyen bir Kurslar sütunu eklendi. Bu razor söz dizimi hakkında daha fazla bilgi için bkz . Açık çizgi geçişi .

  • Seçili eğitmenin tr öğesine dinamik olarak ekleyen class="success" kod eklendi. Bu, Bootstrap sınıfını kullanarak seçili satır için bir arka plan rengi ayarlar.

    string selectedRow = "";
    if (item.CourseID == Model.CourseID)
    {
        selectedRow = "success";
    }
    <tr class="@selectedRow">
    
  • Seç etiketli yeni bir köprü eklendi. Bu bağlantı, seçilen eğitmenin kimliğini yönteme Index gönderir ve bir arka plan rengi ayarlar.

    <a asp-action="Index" asp-route-id="@item.ID">Select</a> |
    

Uygulamayı çalıştırın ve Eğitmenler sekmesini seçin. Sayfada ilgili OfficeAssignment varlıktan Location (office) görüntülenir. OfficeAssignment' null ise boş bir tablo hücresi görüntülenir.

Seç bağlantısına tıklayın. Satır stili değişir.

Seçili eğitmen tarafından öğretilen kursları ekleme

OnGetAsync içindeki Pages/Instructors/Index.cshtml.cs yöntemini aşağıdaki kodla güncelleştirin:

public async Task OnGetAsync(int? id, int? courseID)
{
    Instructor = new InstructorIndexData();
    Instructor.Instructors = await _context.Instructors
          .Include(i => i.OfficeAssignment)
          .Include(i => i.CourseAssignments)
            .ThenInclude(i => i.Course)
                .ThenInclude(i => i.Department)
          .AsNoTracking()
          .OrderBy(i => i.LastName)
          .ToListAsync();

    if (id != null)
    {
        InstructorID = id.Value;
        Instructor instructor = Instructor.Instructors.Where(
            i => i.ID == id.Value).Single();
        Instructor.Courses = instructor.CourseAssignments.Select(s => s.Course);
    }

    if (courseID != null)
    {
        CourseID = courseID.Value;
        Instructor.Enrollments = Instructor.Courses.Where(
            x => x.CourseID == courseID).Single().Enrollments;
    }
}

public int CourseID { get; set; } ekle

public class IndexModel : PageModel
{
    private readonly ContosoUniversity.Data.SchoolContext _context;

    public IndexModel(ContosoUniversity.Data.SchoolContext context)
    {
        _context = context;
    }

    public InstructorIndexData Instructor { get; set; }
    public int InstructorID { get; set; }
    public int CourseID { get; set; }

    public async Task OnGetAsync(int? id, int? courseID)
    {
        Instructor = new InstructorIndexData();
        Instructor.Instructors = await _context.Instructors
              .Include(i => i.OfficeAssignment)
              .Include(i => i.CourseAssignments)
                .ThenInclude(i => i.Course)
                    .ThenInclude(i => i.Department)
              .AsNoTracking()
              .OrderBy(i => i.LastName)
              .ToListAsync();

        if (id != null)
        {
            InstructorID = id.Value;
            Instructor instructor = Instructor.Instructors.Where(
                i => i.ID == id.Value).Single();
            Instructor.Courses = instructor.CourseAssignments.Select(s => s.Course);
        }

        if (courseID != null)
        {
            CourseID = courseID.Value;
            Instructor.Enrollments = Instructor.Courses.Where(
                x => x.CourseID == courseID).Single().Enrollments;
        }
    }

Güncelleştirilmiş sorguyu inceleyin:

Instructor.Instructors = await _context.Instructors
      .Include(i => i.OfficeAssignment)
      .Include(i => i.CourseAssignments)
        .ThenInclude(i => i.Course)
            .ThenInclude(i => i.Department)
      .AsNoTracking()
      .OrderBy(i => i.LastName)
      .ToListAsync();

Yukarıdaki sorgu varlıkları ekler Department .

Bir eğitmen seçildiğinde (id != null aşağıdaki kod yürütülür. Seçilen eğitmen, görünüm modelindeki eğitmenler listesinden alınır. Görünüm modelinin Courses özelliği, eğitmenin CourseCourseAssignments gezinti özelliğindeki varlıklarla birlikte yüklenir.

if (id != null)
{
    InstructorID = id.Value;
    Instructor instructor = Instructor.Instructors.Where(
        i => i.ID == id.Value).Single();
    Instructor.Courses = instructor.CourseAssignments.Select(s => s.Course);
}

Where yöntemi bir koleksiyon döndürür. Önceki Where yöntemde yalnızca tek Instructor bir varlık döndürülür. yöntemi, Single koleksiyonu tek Instructor bir varlığa dönüştürür. varlık Instructor özelliğine CourseAssignments erişim sağlar. CourseAssignments ilgili Course varlıklara erişim sağlar.

Instructor-to-Courses m:M

yöntemi Single , koleksiyonda yalnızca bir öğe olduğunda kullanılır. yöntemi, Single koleksiyon boşsa veya birden fazla öğe varsa bir özel durum oluşturur. Alternatif olarak SingleOrDefault, koleksiyon boşsa varsayılan bir değer (bu örnekte null) döndürür. Boş bir koleksiyonda kullanma SingleOrDefault :

  • Bir özel durumla sonuçlar (null başvuruda bir Courses özelliği bulmaya çalışırken).
  • Özel durum iletisi, sorunun nedenini daha az net gösterir.

Aşağıdaki kod, bir kurs seçildiğinde görünüm modelinin Enrollments özelliğini doldurur:

if (courseID != null)
{
    CourseID = courseID.Value;
    Instructor.Enrollments = Instructor.Courses.Where(
        x => x.CourseID == courseID).Single().Enrollments;
}

Sayfanın sonuna aşağıdaki işaretlemeyi Pages/Instructors/Index.cshtmlRazor ekleyin:

                    <a asp-page="./Delete" asp-route-id="@item.ID">Delete</a>
                </td>
            </tr>
        }
    </tbody>
</table>

@if (Model.Instructor.Courses != null)
{
    <h3>Courses Taught by Selected Instructor</h3>
    <table class="table">
        <tr>
            <th></th>
            <th>Number</th>
            <th>Title</th>
            <th>Department</th>
        </tr>

        @foreach (var item in Model.Instructor.Courses)
        {
            string selectedRow = "";
            if (item.CourseID == Model.CourseID)
            {
                selectedRow = "success";
            }
            <tr class="@selectedRow">
                <td>
                    <a asp-page="./Index" asp-route-courseID="@item.CourseID">Select</a>
                </td>
                <td>
                    @item.CourseID
                </td>
                <td>
                    @item.Title
                </td>
                <td>
                    @item.Department.Name
                </td>
            </tr>
        }

    </table>
}

Yukarıdaki işaretlemede, eğitmen seçildiğinde eğitmenle ilgili derslerin listesi görüntülenir.

Uygulamayı test etme. Eğitmenler sayfasında Bir Seç bağlantısına tıklayın.

Öğrenci verilerini gösterme

Bu bölümde uygulama, seçilen kursun öğrenci verilerini gösterecek şekilde güncelleştirilir.

yöntemindeki Pages/Instructors/Index.cshtml.cs sorguyu OnGetAsync aşağıdaki kodla güncelleştirin:

Instructor.Instructors = await _context.Instructors
      .Include(i => i.OfficeAssignment)                 
      .Include(i => i.CourseAssignments)
        .ThenInclude(i => i.Course)
            .ThenInclude(i => i.Department)
        .Include(i => i.CourseAssignments)
            .ThenInclude(i => i.Course)
                .ThenInclude(i => i.Enrollments)
                    .ThenInclude(i => i.Student)
      .AsNoTracking()
      .OrderBy(i => i.LastName)
      .ToListAsync();

Pages/Instructors/Index.cshtml öğesini güncelleştirin. Dosyanın sonuna aşağıdaki işaretlemeyi ekleyin:


@if (Model.Instructor.Enrollments != null)
{
    <h3>
        Students Enrolled in Selected Course
    </h3>
    <table class="table">
        <tr>
            <th>Name</th>
            <th>Grade</th>
        </tr>
        @foreach (var item in Model.Instructor.Enrollments)
        {
            <tr>
                <td>
                    @item.Student.FullName
                </td>
                <td>
                    @Html.DisplayFor(modelItem => item.Grade)
                </td>
            </tr>
        }
    </table>
}

Yukarıdaki işaretleme, seçili kursa kayıtlı öğrencilerin listesini görüntüler.

Sayfayı yenileyin ve bir eğitmen seçin. Kayıtlı öğrencilerin listesini ve notlarını görmek için bir kurs seçin.

Instructors Index page instructor and course selected

TekLi Kullanma

yöntemi, Single yöntemi ayrı olarak çağırmak yerine koşulunu Where geçirebilirWhere:

public async Task OnGetAsync(int? id, int? courseID)
{
    Instructor = new InstructorIndexData();

    Instructor.Instructors = await _context.Instructors
          .Include(i => i.OfficeAssignment)
          .Include(i => i.CourseAssignments)
            .ThenInclude(i => i.Course)
                .ThenInclude(i => i.Department)
            .Include(i => i.CourseAssignments)
                .ThenInclude(i => i.Course)
                    .ThenInclude(i => i.Enrollments)
                        .ThenInclude(i => i.Student)
          .AsNoTracking()
          .OrderBy(i => i.LastName)
          .ToListAsync();

    if (id != null)
    {
        InstructorID = id.Value;
        Instructor instructor = Instructor.Instructors.Single(
            i => i.ID == id.Value);
        Instructor.Courses = instructor.CourseAssignments.Select(
            s => s.Course);
    }

    if (courseID != null)
    {
        CourseID = courseID.Value;
        Instructor.Enrollments = Instructor.Courses.Single(
            x => x.CourseID == courseID).Enrollments;
    }
}

Yukarıdaki Single yaklaşım, kullanmanın Wherehiçbir avantajını sağlamaz. Bazı geliştiriciler yaklaşım stilini tercih Single eder.

Belirtik yükleme

Geçerli kod ve Studentsiçin Enrollments istekli yüklemeyi belirtir:

Instructor.Instructors = await _context.Instructors
      .Include(i => i.OfficeAssignment)                 
      .Include(i => i.CourseAssignments)
        .ThenInclude(i => i.Course)
            .ThenInclude(i => i.Department)
        .Include(i => i.CourseAssignments)
            .ThenInclude(i => i.Course)
                .ThenInclude(i => i.Enrollments)
                    .ThenInclude(i => i.Student)
      .AsNoTracking()
      .OrderBy(i => i.LastName)
      .ToListAsync();

Kullanıcıların kurstaki kayıtları nadiren görmek istediğini varsayalım. Bu durumda en iyi duruma getirme yalnızca istenen kayıt verilerini yüklemektir. Bu bölümde, OnGetAsync ve Studentsaçık yüklemesini Enrollments kullanacak şekilde güncelleştirilir.

öğesini OnGetAsync aşağıdaki kodla güncelleştirin:

public async Task OnGetAsync(int? id, int? courseID)
{
    Instructor = new InstructorIndexData();
    Instructor.Instructors = await _context.Instructors
          .Include(i => i.OfficeAssignment)                 
          .Include(i => i.CourseAssignments)
            .ThenInclude(i => i.Course)
                .ThenInclude(i => i.Department)
            //.Include(i => i.CourseAssignments)
            //    .ThenInclude(i => i.Course)
            //        .ThenInclude(i => i.Enrollments)
            //            .ThenInclude(i => i.Student)
         // .AsNoTracking()
          .OrderBy(i => i.LastName)
          .ToListAsync();


    if (id != null)
    {
        InstructorID = id.Value;
        Instructor instructor = Instructor.Instructors.Where(
            i => i.ID == id.Value).Single();
        Instructor.Courses = instructor.CourseAssignments.Select(s => s.Course);
    }

    if (courseID != null)
    {
        CourseID = courseID.Value;
        var selectedCourse = Instructor.Courses.Where(x => x.CourseID == courseID).Single();
        await _context.Entry(selectedCourse).Collection(x => x.Enrollments).LoadAsync();
        foreach (Enrollment enrollment in selectedCourse.Enrollments)
        {
            await _context.Entry(enrollment).Reference(x => x.Student).LoadAsync();
        }
        Instructor.Enrollments = selectedCourse.Enrollments;
    }
}

Yukarıdaki kod, kayıt ve öğrenci verileri için ThenInclude yöntemi çağrılarını bırakır. Bir kurs seçiliyse, vurgulanan kod şunları alır:

  • Enrollment Seçili kursun varlıkları.
  • Student Her Enrollmentiçin varlıklar.

Yukarıdaki kodun açıklamalarına .AsNoTracking()dikkat edin. Gezinti özellikleri yalnızca izlenen varlıklar için açıkça yüklenebilir.

Uygulamayı test etme. Kullanıcılar açısından bakıldığında, uygulama önceki sürümle aynı şekilde davranır.

Sonraki öğreticide ilgili verilerin nasıl güncelleştirilecekleri gösterilmektedir.

Ek kaynaklar