ASP.NET MVC 애플리케이션에서 Entity Framework를 사용하여 관련 데이터 읽기(5/10)
작성자: Tom Dykstra
Contoso University 샘플 웹 애플리케이션은 Entity Framework 5 Code First 및 Visual Studio 2012를 사용하여 ASP.NET MVC 4 애플리케이션을 만드는 방법을 보여 줍니다. 자습서 시리즈에 대한 정보는 시리즈의 첫 번째 자습서를 참조하세요.
참고
resolve 수 없는 문제가 발생하면 완료된 장을 다운로드하고 문제를 재현해 보세요. 일반적으로 코드를 완료된 코드와 비교하여 문제에 대한 솔루션을 찾을 수 있습니다. 몇 가지 일반적인 오류 및 해결 방법은 오류 및 해결 방법을 참조하세요.
이전 자습서에서는 School 데이터 모델을 완료했습니다. 이 자습서에서는 관련 데이터, 즉 Entity Framework가 탐색 속성에 로드하는 데이터를 읽고 표시합니다.
다음 그림에서는 사용할 페이지를 보여 줍니다.
관련 데이터의 지연, 열망 및 명시적 로드
Entity Framework는 엔터티의 탐색 속성에 관련 데이터를 로드할 수 있는 여러 가지 방법이 있습니다.
지연 로드. 엔터티를 처음 읽을 때 관련된 데이터가 검색되지 않습니다. 그러나 탐색 속성에 처음으로 액세스하려고 할 때 해당 탐색 속성에 필요한 데이터가 자동으로 검색됩니다. 이렇게 하면 엔터티 자체에 대한 쿼리와 엔터티에 대한 관련 데이터를 검색해야 할 때마다 하나씩 여러 쿼리가 데이터베이스로 전송됩니다.
즉시 로드. 엔터티를 읽을 때 관련된 데이터가 함께 검색됩니다. 이는 일반적으로 필요한 데이터를 모두 검색하는 단일 조인 쿼리를 발생시킵니다. 메서드를 사용하여 즉시 로드를 지정합니다
Include
.명시적 로드. 코드에서 관련 데이터를 명시적으로 검색한다는 점을 제외하고 지연 로드와 비슷합니다. 탐색 속성에 액세스할 때 자동으로 발생하지 않습니다. 엔터티에 대한 개체 상태 관리자 항목을 가져오고 컬렉션에 대한 메서드 또는
Reference.Load
단일 엔터티를 보유하는 속성에 대한 메서드를 호출Collection.Load
하여 관련 데이터를 수동으로 로드합니다. (다음 예제에서는 관리자 탐색 속성을 로드하려는 경우 을Reference(x => x.Administrator)
로 바꿉Collection(x => x.Courses)
니다.)
속성 값을 즉시 검색하지 않으므로 지연 로드 및 명시적 로드를 모두 지연 로드라고도 합니다.
일반적으로 검색된 모든 엔터티에 대한 관련 데이터가 필요하다는 것을 알고 있는 경우 데이터베이스로 전송되는 단일 쿼리가 검색된 각 엔터티에 대한 별도의 쿼리보다 일반적으로 더 효율적이므로 즉시 로드하면 최상의 성능을 제공합니다. 예를 들어 위의 예제에서 각 부서에 10개의 관련 과정이 있다고 가정합니다. 즉시 로드 예제를 사용하면 단일(조인) 쿼리와 데이터베이스로의 단일 왕복만 발생합니다. 지연 로드 및 명시적 로드 예제는 모두 11개의 쿼리와 11번의 데이터베이스 왕복을 초래합니다. 데이터베이스에 대한 추가 왕복은 대기 시간이 길 때 성능에 특히 악영향을 줍니다.
반면에 일부 시나리오에서는 지연 로드가 더 효율적입니다. 즉시 로드하면 매우 복잡한 조인이 생성되어 SQL Server 효율적으로 처리할 수 없습니다. 또는 처리 중인 엔터티 집합의 하위 집합에 대해서만 엔터티의 탐색 속성에 액세스해야 하는 경우 지연 로드는 필요한 것보다 더 많은 데이터를 검색하기 때문에 지연 로드가 더 잘 수행될 수 있습니다. 성능이 중요한 경우 최상의 선택을 위해 두 가지 방식으로 성능을 테스트하는 것이 가장 좋습니다.
일반적으로 지연 로드를 해제한 경우에만 명시적 로드를 사용합니다. 지연 로드를 해제해야 하는 한 가지 시나리오는 serialization 중입니다. 지연 로드 및 serialization은 잘 섞이지 않으며, 주의하지 않으면 지연 로드를 사용하도록 설정할 때 의도한 것보다 훨씬 많은 데이터를 쿼리할 수 있습니다. 직렬화는 일반적으로 형식의 instance 각 속성에 액세스하여 작동합니다. 속성 액세스는 지연 로드를 트리거하고 지연 로드된 엔터티는 직렬화됩니다. 그런 다음 serialization 프로세스는 지연 로드된 엔터티의 각 속성에 액세스하여 더 지연 로드 및 serialization을 유발할 수 있습니다. 이 런어웨이 체인 반응을 방지하려면 엔터티를 직렬화하기 전에 지연 로드를 끕니다.
데이터베이스 컨텍스트 클래스는 기본적으로 지연 로드를 수행합니다. 지연 로드를 사용하지 않도록 설정하는 방법에는 두 가지가 있습니다.
특정 탐색 속성의 경우 속성을 선언할
virtual
때 키워드(keyword) 생략합니다.모든 탐색 속성에 대해 를 로
false
설정합니다LazyLoadingEnabled
. 예를 들어 컨텍스트 클래스의 생성자에 다음 코드를 넣을 수 있습니다.this.Configuration.LazyLoadingEnabled = false;
지연 로드는 성능 문제를 일으키는 코드를 마스킹할 수 있습니다. 예를 들어 열성 또는 명시적 로드를 지정하지 않지만 대량의 엔터티를 처리하고 각 반복에서 여러 탐색 속성을 사용하는 코드는 매우 비효율적일 수 있습니다(데이터베이스로의 많은 왕복으로 인해). 온-프레미스 SQL 서버를 사용하여 개발에서 잘 작동하는 애플리케이션은 대기 시간 증가 및 지연 로드로 인해 Azure SQL Database로 이동할 때 성능 문제가 있을 수 있습니다. 실제 테스트 로드를 사용하여 데이터베이스 쿼리를 프로파일링하면 지연 로드가 적절한지 확인하는 데 도움이 됩니다. 자세한 내용은 Entity Framework 전략 무시: 관련 데이터 로드 및 Entity Framework를 사용하여 네트워크 대기 시간을 줄여 SQL Azure.
부서 이름을 표시하는 과정 인덱스 페이지 만들기
Course
엔터티는 강좌에 할당된 부서의 Department
엔터티를 포함하는 탐색 속성을 포함합니다. 과정 목록에 할당된 부서의 이름을 표시하려면 탐색 속성에 있는 Course.Department
엔터티에서 Department
속성을 가져와 Name
야 합니다.
다음 그림과 같이 이전에 컨트롤러에 대해 했던 Student
것과 동일한 옵션을 사용하여 엔터티 형식에 대한 Course
라는 CourseController
컨트롤러를 만듭니다(이미지와 달리 컨텍스트 클래스는 Models 네임스페이스가 아닌 DAL 네임스페이스에 있음).
Controllers\CourseController.cs를 열고 메서드를 Index
확인합니다.
public ViewResult Index()
{
var courses = db.Courses.Include(c => c.Department);
return View(courses.ToList());
}
자동 스캐폴딩은 Include
메서드를 사용하여 Department
탐색 속성에 대해 즉시 로드를 지정했습니다.
Views\Course\Index.cshtml을 열고 기존 코드를 다음 코드로 바꿉니다. 변경 내용이 강조 표시되어 있습니다.
@model IEnumerable<ContosoUniversity.Models.Course>
@{
ViewBag.Title = "Courses";
}
<h2>Courses</h2>
<p>
@Html.ActionLink("Create New", "Create")
</p>
<table>
<tr>
<th></th>
<th>Number</th>
<th>Title</th>
<th>Credits</th>
<th>Department</th>
</tr>
@foreach (var item in Model) {
<tr>
<td>
@Html.ActionLink("Edit", "Edit", new { id=item.CourseID }) |
@Html.ActionLink("Details", "Details", new { id=item.CourseID }) |
@Html.ActionLink("Delete", "Delete", new { id=item.CourseID })
</td>
<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>
</tr>
}
</table>
스캐폴드 코드에 다음 변경 내용을 만들었습니다.
- 제목을 Index에서 Courses로 변경했습니다.
- 행 링크를 왼쪽으로 이동했습니다.
- 속성 값을 보여 주는 열이 제목 번호 아래에 추가되었습니다
CourseID
. 기본 키는 일반적으로 최종 사용자에게 의미가 없으므로 기본적으로 스캐폴드되지 않습니다. 그러나 이 경우 기본 키는 의미가 있으며 표시하려고 합니다.) - 마지막 열 머리글을 DepartmentID (외래 키
Department
의 이름에서 엔터티로)에서 Department로 변경했습니다.
마지막 열의 경우 스캐폴드된 코드는 탐색 속성에 Department
Department
로드된 엔터티의 속성을 표시 Name
합니다.
<td>
@Html.DisplayFor(modelItem => item.Department.Name)
</td>
페이지를 실행(Contoso University 홈페이지에서 과정 탭 선택)하여 부서 이름이 있는 목록을 확인합니다.
과정 및 등록을 표시하는 강사 인덱스 페이지 만들기
이 섹션에서는 강사 인덱스 페이지를 표시하기 위해 엔터티에 대한 Instructor
컨트롤러와 뷰를 만듭니다.
이 페이지는 다음과 같은 방법으로 관련된 데이터를 읽고 표시합니다.
- 강사 목록은
OfficeAssignment
엔터티에서 관련된 데이터를 표시합니다.Instructor
및OfficeAssignment
엔터티는 일대영 또는 일 관계에 있습니다.OfficeAssignment
엔터티에 대해 즉시 로드를 사용합니다. 이전에 설명한 대로 기본 테이블의 검색된 모든 행에 관련된 데이터가 필요한 경우 즉시 로드는 일반적으로 더 효율적입니다. 이 경우 표시된 모든 강사에 대한 사무실 할당을 표시하길 원합니다. - 사용자가 강사를 선택하면 관련된
Course
엔터티가 표시됩니다.Instructor
및Course
엔터티는 다대다 관계에 있습니다.Course
엔터티 및 관련된Department
엔터티에 대해 즉시 로드를 사용합니다. 이 경우 선택한 강사만 강좌가 필요하므로 지연 로드가 더 효율적일 수 있습니다. 그러나 이 예제에서는 탐색 속성에 있는 엔터티 내에서 탐색 속성에 대한 즉시 로드를 사용하는 방법을 보여 줍니다. - 사용자가 과정을 선택하면
Enrollments
엔터티 집합의 관련 데이터가 표시됩니다.Course
및Enrollment
엔터티는 일대다 관계에 있습니다. 엔터티 및 해당 관련Student
엔터티에 대한Enrollment
명시적 로드를 추가합니다. (지연 로드를 사용하도록 설정했기 때문에 명시적 로드는 필요하지 않지만 명시적 로드를 수행하는 방법을 보여 줍니다.)
강사 인덱스 보기에 대한 보기 모델 만들기
강사 인덱스 페이지에는 세 개의 다른 테이블이 표시됩니다. 따라서 각각이 테이블 중 하나에 대한 데이터를 보유하는 세 가지 속성을 포함하는 보기 모델을 만듭니다.
ViewModels 폴더에서 InstructorIndexData.cs를 만들고 기존 코드를 다음 코드로 바꿉니다.
using System.Collections.Generic;
using ContosoUniversity.Models;
namespace ContosoUniversity.ViewModels
{
public class InstructorIndexData
{
public IEnumerable<Instructor> Instructors { get; set; }
public IEnumerable<Course> Courses { get; set; }
public IEnumerable<Enrollment> Enrollments { get; set; }
}
}
선택한 행에 대한 스타일 추가
선택한 행을 표시하려면 다른 배경색이 필요합니다. 이 UI에 대한 스타일을 제공하려면 아래와 같이 Content\Site.css의 섹션 /* info and errors */
에 강조 표시된 다음 코드를 추가합니다.
/* info and errors */
.selectedrow
{
background-color: #a4d4e6;
}
.message-info {
border: 1px solid;
clear: both;
padding: 10px 20px;
}
강사 컨트롤러 및 뷰 만들기
다음 그림과 InstructorController
같이 컨트롤러를 만듭니다.
Controllers\InstructorController.cs를using
열고 네임스페이 ViewModels
스에 대한 문을 추가합니다.
using ContosoUniversity.ViewModels;
메서드의 Index
스캐폴드된 코드는 탐색 속성에 대해서만 OfficeAssignment
즉시 로드를 지정합니다.
public ViewResult Index()
{
var instructors = db.Instructors.Include(i => i.OfficeAssignment);
return View(instructors.ToList());
}
메서드를 Index
다음 코드로 바꿔 추가 관련 데이터를 로드하고 보기 모델에 넣습니다.
public ActionResult Index(int? id, int? courseID)
{
var viewModel = new InstructorIndexData();
viewModel.Instructors = db.Instructors
.Include(i => i.OfficeAssignment)
.Include(i => i.Courses.Select(c => c.Department))
.OrderBy(i => i.LastName);
if (id != null)
{
ViewBag.InstructorID = id.Value;
viewModel.Courses = viewModel.Instructors.Where(
i => i.InstructorID == id.Value).Single().Courses;
}
if (courseID != null)
{
ViewBag.CourseID = courseID.Value;
viewModel.Enrollments = viewModel.Courses.Where(
x => x.CourseID == courseID).Single().Enrollments;
}
return View(viewModel);
}
메서드는 선택한 강사 및 선택한 과정의 ID 값을 제공하고 필요한 모든 데이터를 뷰에 전달하는 선택적 경로 데이터(id
) 및 쿼리 문자열 매개 변수(courseID
)를 허용합니다. 매개 변수는 페이지의 선택 하이퍼링크에서 제공됩니다.
팁
경로 데이터
경로 데이터는 모델 바인더가 라우팅 테이블에 지정된 URL 세그먼트에서 찾은 데이터입니다. 예를 들어 기본 경로는 , action
및 id
세그먼트를 지정controller
합니다.
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
다음 URL에서 기본 경로는 로 action
Index
매핑 Instructor
controller
되고, 1id
은 로 매핑됩니다. 이러한 경로는 경로 데이터 값입니다.
http://localhost:1230/Instructor/Index/1?courseID=2021
"?courseID=2021"은 쿼리 문자열 값입니다. 를 쿼리 문자열 값으로 전달하는 id
경우에도 모델 바인더가 작동합니다.
http://localhost:1230/Instructor/Index?id=1&CourseID=2021
URL은 Razor 뷰의 문에 의해 ActionLink
만들어집니다. 다음 코드에서 매개 변수는 id
기본 경로와 일치하므로 id
경로 데이터에 추가됩니다.
@Html.ActionLink("Select", "Index", new { id = item.PersonID })
다음 코드에서 는 courseID
기본 경로의 매개 변수와 일치하지 않으므로 쿼리 문자열로 추가됩니다.
@Html.ActionLink("Select", "Index", new { courseID = item.CourseID })
코드는 보기 모델의 인스턴스를 만들고 강사 목록에 배치하여 시작합니다. 코드는 및 탐색 속성에 대한 Instructor.OfficeAssignment
즉시 로드를 Instructor.Courses
지정합니다.
var viewModel = new InstructorIndexData();
viewModel.Instructors = db.Instructors
.Include(i => i.OfficeAssignment)
.Include(i => i.Courses.Select(c => c.Department))
.OrderBy(i => i.LastName);
두 번째 Include
메서드는 Courses를 로드하고 로드되는 각 과정에 대해 탐색 속성에 대한 즉시 로드를 Course.Department
수행합니다.
.Include(i => i.Courses.Select(c => c.Department))
앞에서 설명한 것처럼 즉시 로드할 필요는 없지만 성능을 향상시키기 위해 수행됩니다. 보기는 항상 OfficeAssignment
엔터티가 필요하므로 동일한 쿼리에서 페치하는 것이 더 효율적입니다. Course
웹 페이지에서 강사를 선택할 때 엔터티가 필요하므로 빈도 로드는 페이지가 없는 것보다 선택한 과정으로 더 자주 표시되는 경우에만 지연 로드보다 낫습니다.
강사 ID를 선택한 경우 선택한 강사는 보기 모델의 강사 목록에서 검색됩니다. 뷰 모델의 Courses
속성은 해당 강사의 Courses
탐색 속성에서 Course
엔터티로 로드됩니다.
if (id != null)
{
ViewBag.InstructorID = id.Value;
viewModel.Courses = viewModel.Instructors.Where(i => i.InstructorID == id.Value).Single().Courses;
}
메서드는 Where
컬렉션을 반환하지만, 이 경우 해당 메서드에 전달된 조건에 따라 단일 Instructor
엔터티만 반환됩니다. Single
메서드는 컬렉션을 단일 Instructor
엔터티로 변환합니다. 이는 해당 엔터티의 Courses
속성에 대한 액세스를 제공합니다.
컬렉션에 항목이 하나만 있다는 것을 알고 있는 경우 컬렉션에서 Single 메서드를 사용합니다. 메서드는 Single
전달된 컬렉션이 비어 있거나 둘 이상의 항목이 있는 경우 예외를 throw합니다. 또는 컬렉션이 비어 있는 경우 기본값(null
이 경우)을 반환하는 SingleOrDefault가 있습니다. 그러나 이 경우 여전히 예외가 발생하며(참조에서 속성을 null
찾으 Courses
려고 시도함) 예외 메시지는 문제의 원인을 덜 명확하게 나타냅니다. 메서드를 호출할 때 메서드를 Single
별도로 호출 Where
하는 대신 조건을 전달할 Where
수도 있습니다.
.Single(i => i.InstructorID == id.Value)
위 코드를 아래 코드 대신 사용합니다.
.Where(I => i.InstructorID == id.Value).Single()
다음으로 강좌를 선택한 경우 선택한 강좌가 보기 모델의 강좌 목록에서 검색됩니다. 그런 다음 보기 모델의 Enrollments
속성이 해당 과정의 Enrollments
탐색 속성에 Enrollment
있는 엔터티와 함께 로드됩니다.
if (courseID != null)
{
ViewBag.CourseID = courseID.Value;
viewModel.Enrollments = viewModel.Courses.Where(
x => x.CourseID == courseID).Single().Enrollments;
}
강사 인덱스 보기 수정
Views\Instructor\Index.cshtml에서 기존 코드를 다음 코드로 바꿉니다. 변경 내용은 강조 표시되어 있습니다.
@model ContosoUniversity.ViewModels.InstructorIndexData
@{
ViewBag.Title = "Instructors";
}
<h2>Instructors</h2>
<p>
@Html.ActionLink("Create New", "Create")
</p>
<table>
<tr>
<th></th>
<th>Last Name</th>
<th>First Name</th>
<th>Hire Date</th>
<th>Office</th>
</tr>
@foreach (var item in Model.Instructors)
{
string selectedRow = "";
if (item.InstructorID == ViewBag.InstructorID)
{
selectedRow = "selectedrow";
}
<tr class="@selectedRow" valign="top">
<td>
@Html.ActionLink("Select", "Index", new { id = item.InstructorID }) |
@Html.ActionLink("Edit", "Edit", new { id = item.InstructorID }) |
@Html.ActionLink("Details", "Details", new { id = item.InstructorID }) |
@Html.ActionLink("Delete", "Delete", new { id = item.InstructorID })
</td>
<td>
@item.LastName
</td>
<td>
@item.FirstMidName
</td>
<td>
@Html.DisplayFor(modelItem => item.HireDate)
</td>
<td>
@if (item.OfficeAssignment != null)
{
@item.OfficeAssignment.Location
}
</td>
</tr>
}
</table>
기존 코드에 다음 변경 내용을 만들었습니다.
모델 클래스를
InstructorIndexData
로 변경했습니다.페이지 제목을 인덱스에서 강사로 변경했습니다.
행 링크 열을 왼쪽으로 이동했습니다.
FullName 열을 제거했습니다.
가 null이 아닌 경우에만
item.OfficeAssignment
표시되는item.OfficeAssignment.Location
Office 열이 추가되었습니다. (1 대 0 또는 1 관계이므로 관련OfficeAssignment
엔터티가 없을 수 있습니다.)<td> @if (item.OfficeAssignment != null) { @item.OfficeAssignment.Location } </td>
선택한 강사의 요소에
tr
동적으로 추가할class="selectedrow"
코드가 추가되었습니다. 앞에서 만든 CSS 클래스를 사용하여 선택한 행의 배경색을 설정합니다. (특성은valign
테이블에 여러 행 열을 추가할 때 다음 자습서에서 유용합니다.)string selectedRow = ""; if (item.InstructorID == ViewBag.InstructorID) { selectedRow = "selectedrow"; } <tr class="@selectedRow" valign="top">
각 행의 다른 링크 바로 앞에 Select라는 레이블이 새로
ActionLink
추가되어 선택한 강사 ID가 메서드로Index
전송됩니다.
애플리케이션을 실행하고 강사 탭을 선택합니다. 페이지에는 관련 엔터티가 Location
없는 OfficeAssignment
경우 관련 OfficeAssignment
엔터티 및 빈 테이블 셀의 속성이 표시됩니다.
Views\Instructor\Index.cshtml 파일의 닫는 table
요소(파일 끝에 있음) 다음에 강조 표시된 다음 코드를 추가합니다. 그러면 강사를 선택할 때 강사와 관련된 과정 목록이 표시됩니다.
<td>
@if (item.OfficeAssignment != null)
{
@item.OfficeAssignment.Location
}
</td>
</tr>
}
</table>
@if (Model.Courses != null)
{
<h3>Courses Taught by Selected Instructor</h3>
<table>
<tr>
<th></th>
<th>ID</th>
<th>Title</th>
<th>Department</th>
</tr>
@foreach (var item in Model.Courses)
{
string selectedRow = "";
if (item.CourseID == ViewBag.CourseID)
{
selectedRow = "selectedrow";
}
<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>
}
이 코드는 보기 모델의 Courses
속성을 읽어 강좌의 목록을 표시합니다. 또한 선택한 과정의 ID를 작업 메서드로 보내는 하이퍼링크를 Index
제공합니다Select
.
참고
.css 파일은 브라우저에서 캐시됩니다. 애플리케이션을 실행할 때 변경 내용이 표시되지 않으면 하드 새로 고침을 수행합니다( 새로 고침 단추를 클릭하는 동안 Ctrl 키를 누르거나 Ctrl+F5 누르기).
페이지를 실행하고 강사를 선택합니다. 이제 선택된 강사에 할당된 강좌를 표시하는 표가 표시되고 각 강좌에 대해 할당된 부서의 이름이 표시됩니다.
방금 추가한 코드 블록 뒤에 다음 코드를 추가합니다. 해당 강좌가 선택된 경우에 강좌에 등록된 학생의 목록을 표시합니다.
@if (Model.Enrollments != null)
{
<h3>
Students Enrolled in Selected Course</h3>
<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>
}
이 코드는 강좌에 등록한 학생의 목록을 표시하기 위해 보기 모델의 Enrollments
속성을 읽습니다.
페이지를 실행하고 강사를 선택합니다. 그런 다음, 강좌를 선택하여 등록된 학생 및 해당 등급의 목록을 봅니다.
명시적 로드 추가
InstructorController.cs를 열고 메서드가 Index
선택한 과정의 등록 목록을 가져오는 방법을 살펴봅니다.
if (courseID != null)
{
ViewBag.CourseID = courseID.Value;
viewModel.Enrollments = viewModel.Courses.Where(
x => x.CourseID == courseID).Single().Enrollments;
}
강사 목록을 검색할 때 탐색 속성 및 각 과정의 속성에 대한 Courses
즉시 로드를 Department
지정했습니다. 그런 다음 뷰 모델에 컬렉션을 배치 Courses
하고 이제 해당 컬렉션의 한 엔터티에서 탐색 속성에 액세스합니다 Enrollments
. 탐색 속성에 대한 Course.Enrollments
즉시 로드를 지정하지 않았기 때문에 지연 로드의 결과로 해당 속성의 데이터가 페이지에 표시됩니다.
다른 방법으로 코드를 변경하지 않고 지연 로드를 사용하지 않도록 설정한 경우 속성은 Enrollments
코스의 실제로 등록 수에 관계없이 null이 됩니다. 이 경우 속성을 로드 Enrollments
하려면 즉시 로드 또는 명시적 로드를 지정해야 합니다. 이미 즉시 로드하는 방법을 살펴보았습니다. 명시적 로드 예제를 보려면 메서드를 Index
속성을 명시적으로 로드하는 다음 코드로 바꿉니다 Enrollments
. 변경된 코드가 강조 표시됩니다.
public ActionResult Index(int? id, int? courseID)
{
var viewModel = new InstructorIndexData();
viewModel.Instructors = db.Instructors
.Include(i => i.OfficeAssignment)
.Include(i => i.Courses.Select(c => c.Department))
.OrderBy(i => i.LastName);
if (id != null)
{
ViewBag.InstructorID = id.Value;
viewModel.Courses = viewModel.Instructors.Where(
i => i.InstructorID == id.Value).Single().Courses;
}
if (courseID != null)
{
ViewBag.CourseID = courseID.Value;
var selectedCourse = viewModel.Courses.Where(x => x.CourseID == courseID).Single();
db.Entry(selectedCourse).Collection(x => x.Enrollments).Load();
foreach (Enrollment enrollment in selectedCourse.Enrollments)
{
db.Entry(enrollment).Reference(x => x.Student).Load();
}
viewModel.Enrollments = selectedCourse.Enrollments;
}
return View(viewModel);
}
선택한 Course
엔터티를 가져오면 새 코드는 해당 과정의 Enrollments
탐색 속성을 명시적으로 로드합니다.
db.Entry(selectedCourse).Collection(x => x.Enrollments).Load();
그런 다음 각 Enrollment
엔터티의 관련 Student
엔터티를 명시적으로 로드합니다.
db.Entry(enrollment).Reference(x => x.Student).Load();
메서드를 Collection
사용하여 컬렉션 속성을 로드하지만 엔터티가 하나만 있는 속성의 경우 메서드를 Reference
사용합니다. 이제 강사 인덱스 페이지를 실행할 수 있으며 데이터가 검색되는 방법을 변경했지만 페이지에 표시되는 내용에는 차이가 없습니다.
요약
이제 세 가지 방법(지연, 열망 및 명시적)을 모두 사용하여 관련 데이터를 탐색 속성에 로드했습니다. 다음 자습서에서는 관련된 데이터를 업데이트하는 방법을 설명합니다.
다른 Entity Framework 리소스에 대한 링크는 ASP.NET 데이터 액세스 콘텐츠 맵에서 찾을 수 있습니다.