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:
İ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.
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
Load
ayrı 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. ileLoad
ayrı sorgular, istekli yüklemeden çok açıkça yüklemeye benzer.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. Örneğin: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.
Bir kurs için atanan bölümün adını görüntülemek için:
- İlgili
Department
varlığı gezinti özelliğineCourse.Department
yükleyin. - Varlığın
Department
Name
özelliğinden adı alın.
yapı iskelesi kursu sayfaları
yöntemini açın
Pages/Courses/Index.cshtml.cs
ve inceleyinOnGetAsync
. yapı iskelesi altyapısı gezinti özelliği için istekli yükleme belirttiDepartment
.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
Sayfaları/Kurslar/Index.cshtml.cs 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ı olarakCourses
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ığınDepartment
ö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.
Select ile ilgili verileri yükleme
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 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; }
}
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.
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
veOfficeAssignment
varlıkları bire sıfıra veya bir ilişkisindedir. Varlıklar içinOfficeAssignment
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
veCourse
varlıkları çoka çok ilişkisindedir. Hevesle yükleme, varlıklar ve ilgiliDepartment
varlıkları içinCourse
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
veEnrollment
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ı
Aşağıdaki özel durumlarla öğrenci sayfalarının iskelesini oluşturma başlığı altında yer alan yönergeleri izleyin:
- Sayfalar/Eğitmenler klasörü oluşturun.
- Model sınıfı için kullanın
Instructor
. - Yeni bir tane oluşturmak yerine mevcut bağlam sınıfını kullanın.
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 Course
Courses
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
olarak@page "{id:int?}"
güncelleştirir."{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ülenenitem.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 satır geçişi.
Seçili eğitmenin ve kursun
tr
öğesine dinamik olarak ekleyenclass="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.
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:
İ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öntemleriyleInclude
belirtilir.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
Load
ayrı 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. ileLoad
ayrı sorgular, istekli yüklemeden çok açıkça yüklemeye benzer.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. Örneğin: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.
Bir kurs için atanan bölümün adını görüntülemek için:
- İlgili
Department
varlığı gezinti özelliğineCourse.Department
yükleyin. - Varlığın
Department
Name
özelliğinden adı alın.
yapı iskelesi kursu sayfaları
yöntemini açın
Pages/Courses/Index.cshtml.cs
ve inceleyinOnGetAsync
. yapı iskelesi altyapısı gezinti özelliği için istekli yükleme belirttiDepartment
.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
Sayfaları/Kurslar/Index.cshtml.cs 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ı olarakCourses
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ığınDepartment
ö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.
Select ile ilgili verileri yükleme
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.
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
veOfficeAssignment
varlıkları bire sıfıra veya bir ilişkisindedir. Varlıklar içinOfficeAssignment
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
veCourse
varlıkları çoka çok ilişkisindedir. Hevesle yükleme, varlıklar ve ilgiliDepartment
varlıkları içinCourse
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
veEnrollment
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ı
Aşağıdaki özel durumlarla öğrenci sayfalarının iskelesini oluşturma başlığı altında yer alan yönergeleri izleyin:
- Sayfalar/Eğitmenler klasörü oluşturun.
- Model sınıfı için kullanın
Instructor
. - Yeni bir tane oluşturmak yerine mevcut bağlam sınıfını kullanın.
İ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 Course
için ve ThenInclude
yöntemlerinin yinelenmesine Include
CourseAssignments
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 Course
CourseAssignments
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.
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
olarak@page
@page "{id:int?}"
güncelleştirir."{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ülenenitem.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 satır geçişi.
Seçili eğitmenin ve kursun
tr
öğesine dinamik olarak ekleyenclass="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.
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 Students
iç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 Students
açı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
HerEnrollment
iç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:
İlgili verilerin hevesle, açık ve gecikmeli yüklenmesi
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öntemleriyleInclude
belirtilir.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
Load
ayrı 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. ileLoad
ayrı sorgular, istekli yüklemeden çok açıkça yüklemeye benzer.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. Örneğin: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ığındanDepartment
özelliğini alın.- Varlık
Department
gezinti özelliğindenCourse.Department
gelir.
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ığınDepartment
ö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.
Select ile ilgili verileri yükleme
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.
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
veOfficeAssignment
varlıkları bire sıfıra veya bir ilişkisindedir. Varlıklar içinOfficeAssignment
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
veCourse
varlıkları çoka çok ilişkisindedir. Hevesle yükleme, varlıklar ve ilgiliDepartment
varlıkları içinCourse
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
veEnrollment
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
olarak@page
@page "{id:int?}"
güncelleştirir."{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ülenenitem.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 satır geçişi.
Seçili eğitmenin
tr
öğesine dinamik olarak ekleyenclass="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 Course
CourseAssignments
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.
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.cshtml
Razor 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.
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 Where
hiçbir avantajını sağlamaz. Bazı geliştiriciler yaklaşım stilini tercih Single
eder.
Belirtik yükleme
Geçerli kod ve Students
iç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 Students
açı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
HerEnrollment
iç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
ASP.NET Core