Working with Data » Getting started with ASP.NET Core and Entity Framework Core using Visual Studio

Reading related data

9 of 9 people found this helpful

The Contoso University sample web application demonstrates how to create ASP.NET Core 1.0 MVC web applications using Entity Framework Core 1.0 and Visual Studio 2015. For information about the tutorial series, see the first tutorial in the series.html

In the previous tutorial you completed the School data model. In this tutorial you’ll read and display related data – that is, data that the Entity Framework loads into navigation properties.ios

在前面的教程中,已經完成了關於School的數據模型。在本教程中,將實現對關係數據的讀取和顯示,關係數據是的就是經過EF加載的導航屬性數據。web

The following illustrations show the pages that you’ll work with.數據庫

Courses Index page Instructors Index page

  • Explicit loading. When the entity is first read, related data isn’t retrieved. You write code that retrieves the related data if it’s needed. As in the case of eager loading with separate queries, explicit loading results in multiple queries sent to the database. The difference is that with explicit loading, the code specifies the navigation properties to be loaded. Entity Framework Core 1.0 does not provide an explicit loading API.

  • 顯式加載。當第一次讀取實體時,沒有取回關係數據。在須要時,可編寫取回關係數據的代碼。由於在使用分步查詢進行預加載時,顯示加載的結果是向數據庫發送了複合查詢。區別是,使用顯示加載時指定導航屬性的代碼將被加載。EF Core 1.0不提供顯示加載的API。
  • Lazy loading. When the entity is first read, related data isn’t retrieved. However, the first time you attempt to access a navigation property, the data required for that navigation property is automatically retrieved. A query is sent to the database each time you try to get data from a navigation property for the first time. Entity Framework Core 1.0 does not support lazy loading.

  • 延遲加載。當首次讀取實體時,沒有取回關係數據。然而,你第一次嘗試鏈接導航屬性時,自動取回導航屬性所需的數據。第一次嘗試從導航屬性取得數據時,每次都向數據庫發送一個查詢。EF Core 1.0不支持延遲加載。

Performance considerations 對性能的考慮

If you know you need related data for every entity retrieved, eager loading often offers the best performance, because a single query sent to the database is typically more efficient than separate queries for each entity retrieved. For example, suppose that each department has ten related courses. Eager loading of all related data would result in just a single (join) query and a single round trip to the database. A separate query for courses for each department would result in eleven round trips to the database. The extra round trips to the database are especially detrimental to performance when latency is high.

若是你知道每個取回的實體都須要關係數據,那麼預加載一般提供了最好的性能,由於發到數據庫的單獨查詢一般狀況下比分步查詢更有效率。例如,假定每一個繫有10個關係課程,預加載全部的關係數據會致使僅有一個單獨的(join)查詢,這樣就會在數據庫中進行一次循環。對每一個系的課程執行分步查詢將致使數據庫中11次循環。當潛在因素較高時,數據庫額外的循環特別影響性能。

On the other hand, in some scenarios separate queries is more efficient. Eager loading of all related data in one query might cause a very complex join to be generated, which SQL Server can’t process efficiently. Or if you need to access an entity’s navigation properties only for a subset of a set of the entities you’re processing, separate queries might perform better because eager loading of everything up front would retrieve more data than you need. If performance is critical, it’s best to test performance both ways in order to make the best choice.

另外一方面,在某些場景下分步查詢會更有效率。在一條查詢中預加載全部的關係數據可能致使產生很是複雜的join語句,這使得SQL Server不能高效地執行。或者,若是僅須要使用集合的一個子集的實體導航實行,分步查詢可能執行起來效率更高,由於預加載全部的數據會返回比你須要的更多的數據。若是查詢的性能很是重要,最好測試這兩種方法以便作出正確的選擇。

Create a Courses page that displays Department name 新建顯示系名稱的課程頁面

The Course entity includes a navigation property that contains the Department entity of the department that the course is assigned to. To display the name of the assigned department in a list of courses, you need to get the Name property from the Department entity that is in the Course.Department navigation property.

設計時,課程實體包含了系實體的導航屬性。要在課程列表中顯示指定的系名稱,須要取得Course.Department導航屬性鏈接的系實體相關的Name屬性。

Create a controller named CoursesController for the Course entity type, using the same options for the MVC Controller with views, using Entity Framework scaffolder that you did earlier for the Students controller, as shown in the following illustration:

爲課程實體類型新建一個名爲CoursesController的控制器,使用MVC Controller with views, 使用EF基架生成器,以下圖所示:

Add Courses controller

Open CourseController.cs and examine the Index method. The automatic scaffolding has specified eager loading for the Department navigation property by using the Include method.

Replace the Index method with the following code that uses a more appropriate name for the IQueryable that returns Course entities (courses instead of schoolContext):

打開CourseController.cs文件並對Index方法進行測試。自動搭建的結構爲Department導航屬性指定了預加載模式(使用Include方法)。用下列代碼替換Index方法,使用更恰當的IQueryable返回課程實體(使用courses而不是schoolContext):

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

 

Open Views/Courses/Index.cshtml and replace the template code with the following code. The changes are highlighted:

@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.Credits)
            </th>
            <th>
                @Html.DisplayNameFor(model => model.Title)
            </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.Credits)
                </td>
                <td>
                    @Html.DisplayFor(modelItem => item.Title)
                </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>

 

 

You’ve made the following changes to the scaffolded code:

你已經對自動生成的框架作了以下改動:

  • Changed the heading from Index to Courses.

  • 改變了Course的Index頁面的標頭
  • Added a Number column that shows the CourseID property value. By default, primary keys aren’t scaffolded because normally they are meaningless to end users. However, in this case the primary key is meaningful and you want to show it.

  • 添加一個Number列來顯示CourseID屬性的值。默認狀況下,自動生成的代碼不包含主鍵,由於使用起來一般主鍵是沒有意義的。然而,在這種狀況下主鍵是有意義的,而且你想將其展示出來。
  • Added the Department column. Notice that for the Department column, the code displays the Name property of the Department entity that’s loaded into the Department navigation property:

  • 添加了Department列。注意Department列,顯示系實體的Name屬性的代碼,它加載到Department導航屬性中:

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

     

Run the page (select the Courses tab on the Contoso University home page) to see the list with department names.

運行該頁面(在Home頁面上選擇Courses)查看帶有系名的列表。

Courses Index page

Create an Instructors page that shows Courses and Enrollments 新建Instructors頁面顯示課程和註冊信息

In this section you’ll create a controller and view for the Instructor entity in order to display the Instructors page:

在該節中,你將新建Instructor實體的控制器和視圖,用來顯示Instrctors頁面:

Instructors Index page

This page reads and displays related data in the following ways:

該頁面經過如下方法讀取、顯示關係數據:

  • The list of instructors displays related data from the OfficeAssignment entity. The Instructor and OfficeAssignment entities are in a one-to-zero-or-one relationship. You’ll use eager loading for the OfficeAssignment entities. As explained earlier, eager loading is typically more efficient when you need the related data for all retrieved rows of the primary table. In this case, you want to display office assignments for all displayed instructors.
  • Instuctors列表顯示了來自OfficeAssignment實體的關係數據。Instructor和OfficeAssignment實體之間有1-0-或-1的關係。你將預加載OfficeAssignment實體。先解釋一下,當須要取回主表的全部行時,預加載一般更爲高效。在這裏,你意圖顯示全部的講師及其辦公室安排。
  • When the user selects an instructor, related Course entities are displayed. The Instructor and Course entities are in a many-to-many relationship. You’ll use eager loading for the Course entities and their related Department entities. In this case, separate queries might be more efficient because you need courses only for the selected instructor. However, this example shows how to use eager loading for navigation properties within entities that are themselves in navigation properties.
  • 當用戶選擇一個講師時就會顯示相關的課程實體。講師和課程實體具備多對多的關係。你將使用預加載處理課程實體及其相關的系實體。在這種狀況下,分步查詢可能更高效,由於你僅須要被選擇講師的課程信息。然而,該例子展現瞭如何使用預加載的方式處理實體中的導航屬性,that are themselves in navigation properties???
  • When the user selects a course, related data from the Enrollments entity set is displayed. The Course and Enrollment entities are in a one-to-many relationship. You’ll use separate queries for Enrollment entities and their related Student entities.
  • 當用戶選擇一門課程時,就會顯示來自注冊實體集合中的關係數據。課程和註冊實體具備1對多的關係。你將使用分步查詢來處理註冊實體機器相關的學生實體。

Create a view model for the Instructor Index view 爲Instructor Index視圖新建視圖模型

The Instructors page shows data from three different tables. Therefore, you’ll create a view model that includes three properties, each holding the data for one of the tables.

In the SchoolViewModels folder, create InstructorIndexData.cs and replace the existing code with the following code:

講師頁面顯示的數據來自於三個不一樣的表。所以,你將新建一個視圖模型,其包含三個屬性,每一個屬性控制一個表的數據。

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

 

Create the Instructor controller and views 新建講師控制器和視圖

Create an Instructors controller with EF read/write actions as shown in the following illustration:

用EF read/write動做新建講師控制器,以下圖所示:

Add Instructors controller

Open InstructorsController.cs and add a using statement for the ViewModels namespace:

打開InstructorsController.cs,而且添加using語句:

using ContosoUniversity.Models.SchoolViewModels;

 Replace the Index method with the following code to do eager loading of related data and put it in the view model.

用下列代碼替換Index方法,以實現關係數據的預加載,並將其放置於視圖模型內。

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.Courses)
            .ThenInclude(i => i.Course)
                .ThenInclude(i => i.Enrollments)
                    .ThenInclude(i => i.Student)
          .Include(i => i.Courses)
            .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.Courses.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);
}

 The method accepts optional route data (id) and a query string parameter (courseID) that provide the ID values of the selected instructor and selected course. The parameters are provided by the Select hyperlinks on the page.

 該方法接收了可選的路由數據(id)以及一個查詢字符串參數(courseID),該字符串提供了被選擇講師和課程的ID值。該參數經過頁面上的Select連接提供。

The code begins by creating an instance of the view model and putting in it the list of instructors. The code specifies eager loading for the Instructor.OfficeAssignment and the Instructor.Courses navigation property. Within the Courses property, the Enrollments and Department properties are loaded, and within each Enrollment entity the Student property is loaded.

代碼開始新建了視圖模型實例,並將一個講師列表放入其中。代碼指定預加載Instructor.OfficeAssignmentInstructor.Courses 導航屬性。在Courses 屬性中,加載了EnrollmentsDepartment屬性,同時每一個Enrollment實體中的Student屬性也進行了加載。

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

 

Since the view always requires the OfficeAssignment entity, it’s more efficient to fetch that in the same query. Course entities are required when an instructor is selected in the web page, so a single query is better than multiple queries only if the page is displayed more often with a course selected than without.

由於視圖老是須要OfficeAssignment實體,因此在同一個查詢中獲取這些信息更爲高效。當在頁面中選擇某個講師時就會須要課程實體,因此只有在頁面常常顯示一個被選擇的課程時,使用單獨的查詢比複合查詢更好。

If an instructor was selected, the selected instructor is retrieved from the list of instructors in the view model. The view model’s Courses property is then loaded with the Course entities from that instructor’s Courses navigation property.

若是選擇了一個講師,就會從視圖模型的講師列表中返回該講師。視圖模型中的Course屬性接下來就經過講師實體的Course導航屬性加載了。

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

 

The Where method returns a collection, but in this case the criteria passed to that method result in only a single Instructor entity being returned. The Single method converts the collection into a single Instructor entity, which gives you access to that entity’s Courses property. The Courses property contains CourseInstructor entities, from which you want only the related Course entities.

Where方法返回了一個集合,但這裏的規則是:傳遞給該方法的結果只須要一個單個的講師。Single方法將集合轉化爲一個單獨的講師實體,該實體可以使你鏈接那個實體的Courses屬性。Courses屬性包含了CourseInstructor實體,從該處你只想獲得Course實體的關係數據。

You use the Single method on a collection when you know the collection will have only one item. The Single method throws an exception if the collection passed to it is empty or if there’s more than one item. An alternative is SingleOrDefault, which returns a default value (null in this case) if the collection is empty. However, in this case that would still result in an exception (from trying to find a Courses property on a null reference), and the exception message would less clearly indicate the cause of the problem. When you call the Single method, you can also pass in the Where condition instead of calling the Where method separately:

當知道一個集合僅有一條記錄時,在集合後使用Single方法。若是集合傳遞給它的是空值,或者有超過一條以上的記錄,Single方法就會拋出一個異常。一個相關的方法是SingleOrDefault,若是集合是空集,該方法返回一個默認值(在這裏是null)。然而,在這裏仍然會致使一個異常(來自試圖從一個null引用上尋找一個Courses實體),而且異常信息反應的問題緣由不太清楚。當你調用Single方法時,你也可傳遞一個Where條件,而不是單獨地調用Where方法:

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

 Instead of: 替代:

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

 Next, if a course was selected, the selected course is retrieved from the list of courses in the view model. Then the view model’s Enrollments property is loaded with the Enrollment entities from that course’s Enrollments navigation property.

接下來,若是選擇了一個課程,就會從視圖模型中的課程列表中返回該被選課程。而後,就加載了視圖模型中的Enrollments屬性,同時也就從該課程的Enrollments導航屬性加載了註冊實體。

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

 

Modify the Instructor Index view 修改講師Index視圖

In Views/Instructor/Index.cshtml, replace the template code with the following code. The changes (other than column reordering)are highlighted.注意高亮的修改部分:

@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.Courses) { @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>

 

You’ve made the following changes to the existing code: 已將代碼作了以下變化:

  • Changed the model class to InstructorIndexData. 將模型類變動爲InstructorIndexData

  • Changed the page title from Index to Instructors. 將頁首標題從Index變動爲Instructors。

  • Added an Office column that displays item.OfficeAssignment.Location only if item.OfficeAssignment is not null. (Because this is a one-to-zero-or-one relationship, there might not be a related OfficeAssignment entity.) 增長了Office列,若是item.OfficeAssignment 非空的狀況下,會顯示item.OfficeAssignment.Location ,(由於是1-0或-1的關係,有可能不是一個關係的OfficeAssignment實體)

    @if (item.OfficeAssignment != null)
    {
        @item.OfficeAssignment.Location
    }

     

  • Added a Courses column that displays courses taught by each instructor. 增長了Course列,用於顯示每一個講師講授的課程。

  • Added code that dynamically adds class="success" to the tr element of the selected instructor. This sets a background color for the selected row using a Bootstrap class. 增長了代碼,動態向tr標籤添加被選講師的class=「success」。

    string selectedRow = "";
    if (item.ID == (int?)ViewData["InstructorID"])
    {
        selectedRow = "success";
    }

     

  • Added a new hyperlink labeled Select immediately before the other links in each row, which causes the selected instructor’s ID to be sent to the Index method. 在每行其餘連接後面增長了一個新連接標籤Select,用於將被選講師的ID傳遞給Index方法。

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

     

  • Reordered the columns to display Last Name, First Name, Hire Date, and Office in that order. 記錄的列按照Last Name, First Name, Hire Date, Office的順序進行顯示。

Run the application and select the Instructors tab. The page displays the Location property of related OfficeAssignment entities and an empty table cell when there’s no related OfficeAssignment entity.

運行運用並選擇講師。頁面會就顯示相關OfficeAssignment實體的屬性,若是沒有相關的OfficeAssignment實體就會顯示一個空表。

Instructors Index page nothing selected

In the Views/Instructor/Index.cshtml file, after the closing table element (at the end of the file), add the following code. This code displays a list of courses related to an instructor when an instructor is selected.

Views/Instructor/Index.cshtml文件中,在關閉表格的標籤以後(在文件結尾處),添加下列代碼。當選擇了一個教師時,該代碼顯示一個相關的課程列表。

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

 

This code reads the Courses property of the view model to display a list of courses. It also provides a Select hyperlink that sends the ID of the selected course to the Index action method.

該部分代碼讀取視圖模型的Courses屬性進而顯示課程列表,同時也提供了Select連接,向Index方法發送被選課程的ID。

Run the page and select an instructor. Now you see a grid that displays courses assigned to the selected instructor, and for each course you see the name of the assigned department.

運行該頁面並選擇一個講師。如今你會看到一個表格,顯示了被選講師的課程,你也會看到每一個課程相關的系的名稱。

Instructors Index page instructor selected

After the code block you just added, add the following code. This displays a list of the students who are enrolled in a course when that course is selected.

在剛剛添加的代碼塊後,添加以下代碼。當選擇課程時,就會顯示已註冊該課程的學生列表。

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

 

This code reads the Enrollments property of the view model in order to display a list of students enrolled in the course.

改代碼讀取視圖模型的Enrollments屬性,用於顯示已註冊該課程的學生列表。

Run the page and select an instructor. Then select a course to see the list of enrolled students and their grades.

運行該頁面並選擇一個講師。而後選擇一門課程,看一下已註冊學生的列表和相應的班級。

Instructors Index page instructor and course selected

Use multiple queries 使用複合查詢

When you retrieved the list of instructors in InstructorsController.cs, you specified eager loading for the Courses navigation property.

InstructorsController.cs文件中,當你取回講師列表時,你爲Course導航屬性指定了預加載。

Suppose you expected users to only rarely want to see enrollments in a selected instructor and course. In that case, you might want to load the enrollment data only if it’s requested. To do that you (a) omit eager loading for enrollments when reading instructors, and (b) only when enrollments are needed, call the Load method on an IQueryable that reads the ones you need (starting in EF Core 1.0.1, you can use LoadAsync). EF automatically 「fixes up」 the Courses navigation property of already-retrieved Instructor entities with data retrieved by the Load method.

假定你但願用戶在選擇的講師和課程中不多想看到註冊信息。在這種狀況下,你可能想僅在發出請求時才加載註冊日期。爲了實現這個目的,你會這樣作:

首先:當讀取講師信息時忽略註冊信息的預讀取;

其次:僅當須要註冊信息時,再以IQueryable方式調用Load方法讀取須要的一個數據(從EF Core 1.0.1開始,可使用LoadAsync了)。EF自動「修復」經Load方法已取回的講師實體數據包含的Course導航屬性。

To see this in action, replace the Index method with the following code:

要看一下該方法,用下列代碼替換Index方法:

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.Courses)
            .ThenInclude(i => i.Course)
          .Include(i => i.Courses)
            .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.Courses.Select(s => s.Course);
    }

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

    return View(viewModel);
}

 

The new code drops the ThenInclude method calls for enrollment data from the code that retrieves instructor entities. If an instructor and course are selected, the highlighted code retrieves Enrollment entities for the selected course. With these Enrollment entities, the code eagerly loads the Student navigation property.

新代碼捨棄了ThenInclude方法,而是從已返回的講師實體集合的代碼中調用註冊數據。若是選擇了一個講師和課程,高亮代碼取回被選課程的註冊實體信息。對於這些註冊實體,代碼預加載了學生的導航屬性。

So now, only enrollments taught by the selected instructor in the selected course are retrieved from the database.

因此如今,從數據庫中取回的只是那些在被選課程中的被選講師的講授註冊信息。

Notice that the original query on the Instructors entity set now omits the AsNoTracking method call. Entities must be tracked for EF to 「fix up」 navigation properties when you call the Load method.

注意對講師實體集合的原始查詢如今已經忽略了調用AsNoTarcking方法。對EF來講,調用Load方法時要「修復」導航屬性,實體必須可被跟蹤。

Run the Instructor Index page now and you’ll see no difference in what’s displayed on the page, although you’ve changed how the data is retrieved.

運行講師的Index頁面,你將看到頁面上的顯示沒有什麼不一樣,儘管已經改變了如何取回這些數據的方法。

Summary 總結

You’ve now used eager loading with one query and with multiple queries to read related data into navigation properties. In the next tutorial you’ll learn how to update related data.

如今,你已經使用預讀取的方法執行了單獨查詢和複合查詢,將關係數據讀入導航屬性。在下個教程中,你將學習如何更新關係數據。

 

原文連接

相關文章
相關標籤/搜索