演练5-4:Contoso大学校园管理系统4
在之前的教程中,我们已经完成了学校的数据模型。现在我们将读取和显示相关数据,请理解EF加载导航属性的方式。
一、Lazy、Eager、Explicit数据加载
使用EF为实体中的导航属性加载相关数据,有下面几种方法。
1.Lazy loading
当实体第一次读取时,相关数据并没有获得。然而当你第一次想要访问导航属性时,导航属性的相关数据会自动获得。这产生了多次访问数据库,一次是实体数据读取,一次是导航属性读取。
2.Eager loading
当实体读取时,相关数据也一起读取,使用Include方法实现。这是通过join数据表,查询获取需要的数据。
3.Explicit loading
当你访问导航属性时,相关数据不会自动获取。你需要在代码中显式获取相关数据。
Lazying loading和Explicit Loading都称为延迟加载。
4.讨论
哪个方法性能最好?
- 读取数据库的次数比较
- 不需要读取全部记录
- 关联过于复杂
lazy loading 和 serialization不兼容,如果需要关闭lazy loading,可以使用下面两个方法:
(1)导航属性声明时,去掉virtual;
(2)在context类的构造函数中,加上下面的代码。
this.Configuration.LazyLoadingEnabled = false;
二、创建课程页面
1.小手动起来,生成这个页面
2.做一些改动
(1)将<h2>标题从Index改为Courses
(2)将row links放到左边
(3)为Number属性添加一个列
(4)改变列标题DepartmentID为Department
3.看看加载方式
public ViewResult Index() { var courses = db.Courses.Include(c => c.Department); return View(courses.ToList()); }
<td> @Html.DisplayFor(modelItem => item.Department.Name) </td>
三、创建教师页面
1.为教师页面创建视图模型
创建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; } } }
2.为选中的行,添加样式
在Content\Site.css文件中添加样式。
/* info and errors */ .selectedrow { background-color: #a4d4e6; } .message-info { border: 1px solid; clear: both; padding: 10px 20px; }
3.创建教师控制器和视图
(1)更改Controllers\InstructorController.cs文件
using ContosoUniversity.ViewModels;
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); }
(2)分析数据加载
OfficeAssignment:它与Intructor之间是一对一的关系,我们采用了eager loading方式加载数据。因为这样做效率高,并且需要老师的OfficeAssignment都需要显示。
Course:选中某老师后,显示相关的课程信息。它与Instructor之间是多对多的关系。此处采用了eager loading方式加载数据,实际上lazy loading会更有效率,因为只需要显示选中的教师课程信息。
Enrollment:当选择了某个老师某门课程之后,相关的选修情况就会出现。Course与Enrollment之间是一对多的关系。此处采用了lazy loading方式,以后我们会换用explicit loading方式。
(3)修改教师Index视图
在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>
(4)显示老师相关的课程
在Views\Instructor\Index.cshtml文件中添加代码。
<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> }
(5)显示某老师教的某课程的选修情况
在Views\Instructor\Index.cshtml页面中添加代码
@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> }
四、显式数据加载
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); }