Bagikan melalui


Tutorial: Membaca data terkait - ASP.NET MVC dengan EF Core

Dalam tutorial sebelumnya, Anda menyelesaikan model data Sekolah. Dalam tutorial ini, Anda akan membaca dan menampilkan data terkait -- yaitu, data yang dimuat Kerangka Kerja Entitas ke dalam properti navigasi.

Ilustrasi berikut ini memperlihatkan halaman yang akan Anda kerjakan.

Courses Index page

Instructors Index page

Di tutorial ini, Anda akan:

  • Pelajari cara memuat data terkait
  • Membuat halaman Kursus
  • Membuat halaman Instruktur
  • Pelajari tentang pemuatan eksplisit

Prasyarat

Ada beberapa cara agar perangkat lunak Object-Relational Mapping (ORM) seperti Entity Framework dapat memuat data terkait ke dalam properti navigasi entitas:

  • Pemuatan bersemangat: Saat entitas dibaca, data terkait diambil bersama dengannya. Ini biasanya menghasilkan satu kueri gabungan yang mengambil semua data yang diperlukan. Anda menentukan pemuatan bersemangat di Entity Framework Core dengan menggunakan Include metode dan ThenInclude .

    Eager loading example

    Anda dapat mengambil beberapa data dalam kueri terpisah, dan EF "memperbaiki" properti navigasi. Artinya, EF secara otomatis menambahkan entitas yang diambil secara terpisah tempat entitas tersebut berada di properti navigasi entitas yang diambil sebelumnya. Untuk kueri yang mengambil data terkait, Anda bisa menggunakan Load metode alih-alih metode yang mengembalikan daftar atau objek, seperti ToList atau Single.

    Separate queries example

  • Pemuatan eksplisit: Saat entitas pertama kali dibaca, data terkait tidak diambil. Anda menulis kode yang mengambil data terkait jika diperlukan. Seperti dalam kasus pemuatan bersemangat dengan kueri terpisah, pemuatan eksplisit menghasilkan beberapa kueri yang dikirim ke database. Perbedaannya adalah dengan pemuatan eksplisit, kode menentukan properti navigasi yang akan dimuat. Di Entity Framework Core 1.1 Anda dapat menggunakan Load metode untuk melakukan pemuatan eksplisit. Contohnya:

    Explicit loading example

  • Pemuatan malas: Saat entitas pertama kali dibaca, data terkait tidak diambil. Namun, pertama kali Anda mencoba mengakses properti navigasi, data yang diperlukan untuk properti navigasi tersebut diambil secara otomatis. Kueri dikirim ke database setiap kali Anda mencoba mendapatkan data dari properti navigasi untuk pertama kalinya. Entity Framework Core 1.0 tidak mendukung pemuatan malas.

Pertimbangan performa

Jika Anda tahu bahwa Anda memerlukan data terkait untuk setiap entitas yang diambil, pemuatan bersemangat sering menawarkan performa terbaik, karena satu kueri yang dikirim ke database biasanya lebih efisien daripada kueri terpisah untuk setiap entitas yang diambil. Misalnya, setiap departemen memiliki sepuluh kursus terkait. Pemuatan bersemangat dari semua data terkait hanya akan menghasilkan satu kueri (gabungan) dan satu perjalanan pulang pergi ke database. Kueri terpisah untuk kursus untuk setiap departemen akan menghasilkan sebelas perjalanan pulang pergi ke database. Perjalanan pulang pergi ekstra ke database sangat merugikan performa ketika latensi tinggi.

Di sisi lain, dalam beberapa skenario kueri terpisah lebih efisien. Pemuatan bersemangat dari semua data terkait dalam satu kueri dapat menyebabkan gabungan yang sangat kompleks dihasilkan, yang tidak dapat diproses oleh SQL Server secara efisien. Atau jika Anda perlu mengakses properti navigasi entitas hanya untuk subset sekumpulan entitas yang Anda pemrosesan, kueri terpisah mungkin berkinerja lebih baik karena pemuatan yang bersemangat dari segala sesuatu di muka akan mengambil lebih banyak data daripada yang Anda butuhkan. Jika performa sangat penting, yang terbaik adalah menguji performa kedua cara untuk membuat pilihan terbaik.

Membuat halaman Kursus

Entitas Course mencakup properti navigasi yang berisi Department entitas departemen tempat kursus ditetapkan. Untuk menampilkan nama departemen yang ditetapkan dalam daftar kursus, Anda perlu mendapatkan Name properti dari Department entitas yang ada di Course.Department properti navigasi.

Buat pengontrol bernama CoursesController untuk Course jenis entitas, menggunakan opsi yang sama untuk Pengontrol MVC dengan tampilan, menggunakan perancah Kerangka Kerja Entitas yang Anda lakukan sebelumnya untuk StudentsController, seperti yang ditunjukkan dalam ilustrasi berikut:

Add Courses controller

Buka CoursesController.cs dan periksa metode .Index Perancah otomatis telah menentukan pemuatan bersemangat untuk Department properti navigasi dengan menggunakan Include metode .

Index Ganti metode dengan kode berikut yang menggunakan nama yang lebih sesuai untuk IQueryable yang mengembalikan entitas Kursus (courses bukan schoolContext):

public async Task<IActionResult> Index()
{
    var courses = _context.Courses
        .Include(c => c.Department)
        .AsNoTracking();
    return View(await courses.ToListAsync());
}

Buka Views/Courses/Index.cshtml dan ganti kode templat dengan kode berikut. Perubahan disorot:

@model IEnumerable<ContosoUniversity.Models.Course>

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

<h2>Courses</h2>

<p>
    <a asp-action="Create">Create New</a>
</p>
<table class="table">
    <thead>
        <tr>
            <th>
                @Html.DisplayNameFor(model => model.CourseID)
            </th>
            <th>
                @Html.DisplayNameFor(model => model.Title)
            </th>
            <th>
                @Html.DisplayNameFor(model => model.Credits)
            </th>
            <th>
                @Html.DisplayNameFor(model => model.Department)
            </th>
            <th></th>
        </tr>
    </thead>
    <tbody>
        @foreach (var item in Model)
        {
            <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-action="Edit" asp-route-id="@item.CourseID">Edit</a> |
                    <a asp-action="Details" asp-route-id="@item.CourseID">Details</a> |
                    <a asp-action="Delete" asp-route-id="@item.CourseID">Delete</a>
                </td>
            </tr>
        }
    </tbody>
</table>

Anda telah membuat perubahan berikut pada kode perancah:

  • Mengubah judul dari Indeks ke Kursus.

  • Menambahkan kolom Angka yang memperlihatkan CourseID nilai properti. Secara default, kunci primer tidak di-scaffolding karena biasanya tidak berarti bagi pengguna akhir. Namun, dalam hal ini kunci primer bermakna dan Anda ingin menunjukkannya.

  • Mengubah kolom Departemen untuk menampilkan nama departemen. Kode menampilkan Name properti entitas yang dimuat Department ke Department dalam properti navigasi:

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

Jalankan aplikasi dan pilih tab Kursus untuk melihat daftar dengan nama departemen.

Courses Index page

Membuat halaman Instruktur

Di bagian ini, Anda akan membuat pengontrol dan menampilkan entitas Instructor untuk menampilkan halaman Instruktur:

Instructors Index page

Halaman ini membaca dan menampilkan data terkait dengan cara berikut:

  • Daftar instruktur menampilkan data terkait dari OfficeAssignment entitas. Entitas Instructor dan OfficeAssignment berada dalam hubungan satu-ke-nol-atau-satu. Anda akan menggunakan pemuatan bersemangat untuk OfficeAssignment entitas. Seperti yang dijelaskan sebelumnya, pemuatan bersemangat biasanya lebih efisien ketika Anda memerlukan data terkait untuk semua baris tabel utama yang diambil. Dalam hal ini, Anda ingin menampilkan tugas kantor untuk semua instruktur yang ditampilkan.

  • Saat pengguna memilih instruktur, entitas terkait Course ditampilkan. Entitas Instructor dan Course berada dalam hubungan banyak ke banyak. Anda akan menggunakan pemuatan bersemangat untuk Course entitas dan entitas terkaitnya Department . Dalam hal ini, kueri terpisah mungkin lebih efisien karena Anda hanya memerlukan kursus untuk instruktur yang dipilih. Namun, contoh ini menunjukkan cara menggunakan pemuatan bersemangat untuk properti navigasi dalam entitas yang berada di properti navigasi.

  • Saat pengguna memilih kursus, data terkait dari Enrollments kumpulan entitas ditampilkan. Entitas Course dan Enrollment berada dalam hubungan satu-ke-banyak. Anda akan menggunakan kueri terpisah untuk Enrollment entitas dan entitas terkaitnya Student .

Membuat model tampilan untuk tampilan Indeks Instruktur

Halaman Instruktur memperlihatkan data dari tiga tabel berbeda. Oleh karena itu, Anda akan membuat model tampilan yang menyertakan tiga properti, masing-masing menyimpan data untuk salah satu tabel.

Di folder SchoolViewModels, buat InstructorIndexData.cs dan ganti kode yang ada dengan kode berikut:

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

Membuat pengontrol dan tampilan Instruktur

Buat pengontrol Instruktur dengan tindakan baca/tulis EF seperti yang ditunjukkan dalam ilustrasi berikut:

Add Instructors controller

Buka InstructorsController.cs dan tambahkan pernyataan penggunaan untuk namespace ViewModels:

using ContosoUniversity.Models.SchoolViewModels;

Ganti metode Indeks dengan kode berikut untuk melakukan pemuatan data terkait yang bersemangat dan letakkan dalam model tampilan.

public async Task<IActionResult> Index(int? id, int? courseID)
{
    var viewModel = new InstructorIndexData();
    viewModel.Instructors = await _context.Instructors
          .Include(i => i.OfficeAssignment)
          .Include(i => i.CourseAssignments)
            .ThenInclude(i => i.Course)
                .ThenInclude(i => i.Enrollments)
                    .ThenInclude(i => i.Student)
          .Include(i => i.CourseAssignments)
            .ThenInclude(i => i.Course)
                .ThenInclude(i => i.Department)
          .AsNoTracking()
          .OrderBy(i => i.LastName)
          .ToListAsync();
    
    if (id != null)
    {
        ViewData["InstructorID"] = id.Value;
        Instructor instructor = viewModel.Instructors.Where(
            i => i.ID == id.Value).Single();
        viewModel.Courses = instructor.CourseAssignments.Select(s => s.Course);
    }

    if (courseID != null)
    {
        ViewData["CourseID"] = courseID.Value;
        viewModel.Enrollments = viewModel.Courses.Where(
            x => x.CourseID == courseID).Single().Enrollments;
    }

    return View(viewModel);
}

Metode ini menerima data rute opsional (id) dan parameter string kueri (courseID) yang menyediakan nilai ID dari instruktur yang dipilih dan kursus yang dipilih. Parameter disediakan oleh Pilih hyperlink di halaman.

Kode dimulai dengan membuat instans model tampilan dan memasukkannya ke dalam daftar instruktur. Kode menentukan pemuatan bersemangat Instructor.OfficeAssignment untuk properti navigasi dan Instructor.CourseAssignments . CourseAssignments Dalam properti, Course properti dimuat, dan di dalamnya, Enrollments properti dan Department dimuat, dan di dalam setiap Enrollment entitas Student properti dimuat.

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

Karena tampilan selalu memerlukan OfficeAssignment entitas, lebih efisien untuk mengambilnya dalam kueri yang sama. Entitas kursus diperlukan ketika instruktur dipilih di halaman web, sehingga satu kueri lebih baik daripada beberapa kueri hanya jika halaman ditampilkan lebih sering dengan kursus dipilih daripada tanpa.

Kode berulang CourseAssignments dan Course karena Anda memerlukan dua properti dari Course. String ThenInclude panggilan pertama mendapatkan CourseAssignment.Course, , Course.Enrollmentsdan Enrollment.Student.

Anda dapat membaca selengkapnya tentang menyertakan beberapa tingkat data terkait di sini.

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

Pada titik itu dalam kode, yang lain ThenInclude adalah untuk properti Studentnavigasi , yang tidak Anda butuhkan. Tetapi panggilan Include dimulai kembali dengan Instructor properti, jadi Anda harus melalui rantai lagi, kali ini menentukan Course.Department alih-alih Course.Enrollments.

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

Kode berikut dijalankan ketika instruktur dipilih. Instruktur yang dipilih diambil dari daftar instruktur dalam model tampilan. Properti model Courses tampilan kemudian dimuat dengan Course entitas dari properti navigasi instruktur tersebut CourseAssignments .

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

Metode mengembalikan Where koleksi, tetapi dalam hal ini kriteria yang diteruskan ke metode tersebut hanya menghasilkan satu entitas Instruktur yang dikembalikan. Metode ini Single mengonversi koleksi menjadi satu Instructor entitas, yang memberi Anda akses ke properti entitas tersebut CourseAssignments . Properti CourseAssignments berisi CourseAssignment entitas, dari mana Anda hanya menginginkan entitas terkait Course .

Anda menggunakan metode pada Single koleksi ketika Anda tahu koleksi hanya akan memiliki satu item. Metode Single ini melemparkan pengecualian jika koleksi yang diteruskan ke dalamnya kosong atau jika ada lebih dari satu item. Alternatifnya adalah SingleOrDefault, yang mengembalikan nilai default (null dalam kasus ini) jika koleksi kosong. Namun, dalam hal ini yang masih akan mengakibatkan pengecualian (dari mencoba menemukan Courses properti pada referensi null), dan pesan pengecualian akan kurang jelas menunjukkan penyebab masalah. Ketika Anda memanggil Single metode , Anda juga dapat meneruskan kondisi Di mana alih-alih memanggil Where metode secara terpisah:

.Single(i => i.ID == id.Value)

Alih-alih:

.Where(i => i.ID == id.Value).Single()

Selanjutnya, jika kursus dipilih, kursus yang dipilih diambil dari daftar kursus dalam model tampilan. Kemudian properti model Enrollments tampilan dimuat dengan entitas Pendaftaran dari properti navigasi kursus tersebut Enrollments .

if (courseID != null)
{
    ViewData["CourseID"] = courseID.Value;
    viewModel.Enrollments = viewModel.Courses.Where(
        x => x.CourseID == courseID).Single().Enrollments;
}

Pelacakan vs tanpa pelacakan

Kueri tanpa pelacakan berguna saat hasilnya digunakan dalam skenario baca-saja. Mereka umumnya lebih cepat untuk dijalankan karena tidak perlu menyiapkan informasi pelacakan perubahan. Jika entitas yang diambil dari database tidak perlu diperbarui, maka kueri tanpa pelacakan kemungkinan akan berkinerja lebih baik daripada kueri pelacakan.

Dalam beberapa kasus, kueri pelacakan lebih efisien daripada kueri tanpa pelacakan. Untuk informasi selengkapnya, lihat Melacak vs. Kueri Tanpa Pelacakan.

Mengubah tampilan Indeks Instruktur

Di Views/Instructors/Index.cshtml, ganti kode templat dengan kode berikut. Perubahan disorot.

@model ContosoUniversity.Models.SchoolViewModels.InstructorIndexData

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

<h2>Instructors</h2>

<p>
    <a asp-action="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.Instructors)
        {
            string selectedRow = "";
            if (item.ID == (int?)ViewData["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-action="Index" asp-route-id="@item.ID">Select</a> |
                    <a asp-action="Edit" asp-route-id="@item.ID">Edit</a> |
                    <a asp-action="Details" asp-route-id="@item.ID">Details</a> |
                    <a asp-action="Delete" asp-route-id="@item.ID">Delete</a>
                </td>
            </tr>
           }
    </tbody>
</table>
@model ContosoUniversity.Models.SchoolViewModels.InstructorIndexData

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

<h2>Instructors</h2>

<p>
    <a asp-action="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.Instructors)
        {
            string selectedRow = "";
            if (item.ID == (int?)ViewData["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-action="Index" asp-route-id="@item.ID">Select</a> |
                    <a asp-action="Edit" asp-route-id="@item.ID">Edit</a> |
                    <a asp-action="Details" asp-route-id="@item.ID">Details</a> |
                    <a asp-action="Delete" asp-route-id="@item.ID">Delete</a>
                </td>
            </tr>
           }
    </tbody>
</table>

Anda telah membuat perubahan berikut pada kode yang ada:

  • Mengubah kelas model menjadi InstructorIndexData.

  • Mengubah judul halaman dari Indeks menjadi Instruktur.

  • Menambahkan kolom Office yang hanya ditampilkan item.OfficeAssignment.Location jika item.OfficeAssignment tidak null. (Karena ini adalah hubungan satu-ke-nol-atau-satu, mungkin tidak ada entitas OfficeAssignment terkait.)

    @if (item.OfficeAssignment != null)
    {
        @item.OfficeAssignment.Location
    }
    
  • Menambahkan kolom Kursus yang menampilkan kursus yang diajarkan oleh setiap instruktur. Untuk informasi selengkapnya, lihat bagian Transisi baris eksplisit dari Razor artikel sintaks.

  • Menambahkan kode yang secara kondisional menambahkan kelas Bootstrap CSS ke tr elemen instruktur yang dipilih. Kelas ini mengatur warna latar belakang untuk baris yang dipilih.

  • Menambahkan hyperlink baru berlabel Pilih segera sebelum tautan lain di setiap baris, yang menyebabkan ID instruktur yang dipilih dikirim ke Index metode .

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

Jalankan aplikasi dan pilih tab Instruktur . Halaman menampilkan properti Lokasi entitas OfficeAssignment terkait dan sel tabel kosong saat tidak ada entitas OfficeAssignment terkait.

Instructors Index page nothing selected

Views/Instructors/Index.cshtml Dalam file, setelah elemen tabel penutupan (di akhir file), tambahkan kode berikut. Kode ini menampilkan daftar kursus yang terkait dengan instruktur saat instruktur dipilih.


@if (Model.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.Courses)
        {
            string selectedRow = "";
            if (item.CourseID == (int?)ViewData["CourseID"])
            {
                selectedRow = "success";
            }
            <tr class="@selectedRow">
                <td>
                    @Html.ActionLink("Select", "Index", new { courseID = item.CourseID })
                </td>
                <td>
                    @item.CourseID
                </td>
                <td>
                    @item.Title
                </td>
                <td>
                    @item.Department.Name
                </td>
            </tr>
        }

    </table>
}

Kode ini membaca Courses properti model tampilan untuk menampilkan daftar kursus. Ini juga menyediakan hyperlink Pilih yang mengirim ID kursus yang dipilih ke Index metode tindakan.

Refresh halaman dan pilih instruktur. Sekarang Anda melihat kisi yang menampilkan kursus yang ditetapkan ke instruktur yang dipilih, dan untuk setiap kursus Anda melihat nama departemen yang ditetapkan.

Instructors Index page instructor selected

Setelah blok kode yang baru saja Anda tambahkan, tambahkan kode berikut. Ini menampilkan daftar siswa yang terdaftar dalam kursus ketika kursus tersebut dipilih.

@if (Model.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.Enrollments)
        {
            <tr>
                <td>
                    @item.Student.FullName
                </td>
                <td>
                    @Html.DisplayFor(modelItem => item.Grade)
                </td>
            </tr>
        }
    </table>
}

Kode ini membaca Enrollments properti model tampilan untuk menampilkan daftar siswa yang terdaftar dalam kursus.

Refresh halaman lagi dan pilih instruktur. Kemudian pilih kursus untuk melihat daftar siswa terdaftar dan nilai mereka.

Instructors Index page instructor and course selected

Tentang pemuatan eksplisit

Ketika Anda mengambil daftar instruktur di InstructorsController.cs, Anda menentukan pemuatan bersemangat untuk CourseAssignments properti navigasi.

Misalkan Anda mengharapkan pengguna untuk hanya jarang ingin melihat pendaftaran dalam instruktur dan kursus yang dipilih. Dalam hal ini, Anda mungkin ingin memuat data pendaftaran hanya jika diminta. Untuk melihat contoh cara melakukan pemuatan eksplisit, ganti Index metode dengan kode berikut, yang menghapus pemuatan bersemangat untuk Enrollments dan memuat properti tersebut secara eksplisit. Perubahan kode disorot.

public async Task<IActionResult> Index(int? id, int? courseID)
{
    var viewModel = new InstructorIndexData();
    viewModel.Instructors = await _context.Instructors
          .Include(i => i.OfficeAssignment)
          .Include(i => i.CourseAssignments)
            .ThenInclude(i => i.Course)
                .ThenInclude(i => i.Department)
          .OrderBy(i => i.LastName)
          .ToListAsync();

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

    if (courseID != null)
    {
        ViewData["CourseID"] = courseID.Value;
        var selectedCourse = viewModel.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();
        }
        viewModel.Enrollments = selectedCourse.Enrollments;
    }

    return View(viewModel);
}

Kode baru menghilangkan ThenInclude panggilan metode untuk data pendaftaran dari kode yang mengambil entitas instruktur. Ini juga menjatuhkan AsNoTracking. Jika instruktur dan kursus dipilih, kode yang disorot Enrollment mengambil entitas untuk kursus yang dipilih, dan Student entitas untuk setiap Enrollment.

Jalankan aplikasi, buka halaman Indeks Instruktur sekarang dan Anda tidak akan melihat perbedaan apa yang ditampilkan di halaman, meskipun Anda telah mengubah cara data diambil.

Mendapatkan kode

Unduh atau lihat aplikasi yang telah selesai.

Langkah berikutnya

Di tutorial ini, Anda akan:

  • Mempelajari cara memuat data terkait
  • Membuat halaman Kursus
  • Membuat halaman Instruktur
  • Dipelajari tentang pemuatan eksplisit

Lanjutkan ke tutorial berikutnya untuk mempelajari cara memperbarui data terkait.