通过上一篇的学习 我们把demo的各种关系终于搭建里起来 以及处理好了如何映射到数据库等问题 但是 只是搭建好了关系 问题还远没有解决
这篇就来写如何查找导航属性 和查找导航属性的几种方式 已经跟踪生成的SQL来检测是否满意 通过这节学习 来明白什么时候用哪个~~
一.三种加载
1.延迟加载
这是原文中的图 大家可以去看下 我模仿上面的做了个测试 出现了 已有打开的与此 Command 相关联的 DataReader,必须首先将它关闭。
我的解决办法是 var departments = db.Departments.ToList(); 现读取出来 然后再遍历. 而不加ToList() 真正执行SQL语句在 foreach的时候
然后再说下 这样写以后 SQL语句的执行
1.上来先查询出所有的Department
SELECT [Extent1].[DepartmentID] AS [DepartmentID], [Extent1].[Name] AS [Name], [Extent1].[Budget] AS [Budget], [Extent1].[StartDate] AS [StartDate], [Extent1].[InstructorID] AS [InstructorID] FROM [dbo].[Department] AS [Extent1]
2.再执行到内层foreach时 这个会执行多次 每次@EntityKeyValue1 等于 迭代到这次的 DepartmentID
exec sp_executesql N'SELECT [Extent1].[CourseID] AS [CourseID], [Extent1].[Title] AS [Title], [Extent1].[Credits] AS [Credits], [Extent1].[DepartmentID] AS [DepartmentID] FROM [dbo].[Course] AS [Extent1] WHERE [Extent1].[DepartmentID] = @EntityKeyValue1',N'@EntityKeyValue1 int',@EntityKeyValue1=1
也就是说 我们有多少条Department 就要执行多少次上面的方法 当然 这里使用的是exec sp_executesql 利用sp_executesql,能够重用执行计划,这就大大提供了执行性能
2.贪婪加载
在执行到第一个foreach 时 就执行了SQL语句 这是EF帮我们生成的
SELECT [Project1].[DepartmentID] AS [DepartmentID], [Project1].[Name] AS [Name], [Project1].[Budget] AS [Budget], [Project1].[StartDate] AS [StartDate], [Project1].[InstructorID] AS [InstructorID], [Project1].[C1] AS [C1], [Project1].[CourseID] AS [CourseID], [Project1].[Title] AS [Title], [Project1].[Credits] AS [Credits], [Project1].[DepartmentID1] AS [DepartmentID1] FROM ( SELECT [Extent1].[DepartmentID] AS [DepartmentID], [Extent1].[Name] AS [Name], [Extent1].[Budget] AS [Budget], [Extent1].[StartDate] AS [StartDate], [Extent1].[InstructorID] AS [InstructorID], [Extent2].[CourseID] AS [CourseID], [Extent2].[Title] AS [Title], [Extent2].[Credits] AS [Credits], [Extent2].[DepartmentID] AS [DepartmentID1], CASE WHEN ([Extent2].[CourseID] IS NULL) THEN CAST(NULL AS int) ELSE 1 END AS [C1] FROM [dbo].[Department] AS [Extent1] LEFT OUTER JOIN [dbo].[Course] AS [Extent2] ON [Extent1].[DepartmentID] = [Extent2].[DepartmentID] ) AS [Project1] ORDER BY [Project1].[DepartmentID] ASC, [Project1].[C1] ASC
3.显示加载
先看图
这个我测试后 效果是和第一个一样的 并没有看出什么好处? 期待高手指点下
英文好的也可以看下原文
4.关闭延迟加载
如果我们想启用延迟加载 可以通过这两种方式
1.去掉属性里的virtual
2.context.Configuration.LazyLoadingEnabled = false;
二.实战开始 创建教师页
先上实现后的效果图
从图中 我们可以看出这个要处理的关系
1对1的 教师和办公地点
1对多的 教师教的课程
普通的多对多的
多对多的(关系表里有数据的) 课程和学生 查看选择课程的学生和学分
1.创建viewmodel
有时 我们的页面 显示的不是一个实体类的内容 这个时候我们可以创建一个ViewModel 来展示界面
using System; 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.创建控制器添加Index
public ActionResult Index(Int32? id, Int32? 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); }
先看进来访问的这一块
viewModel.Instructors = db.Instructors .Include(i => i.OfficeAssignment) .Include(i => i.Courses.Select(c => c.Department)) .OrderBy(i => i.LastName);
从最上面的图中 我们可以看到 要显示有教师信息 办公地址 和所教课程
于是 我们使用贪婪加载出办公地址和课程 但是 原文教程里 还Select(c => c.Department) 把院系也一起加载了进来 我认为这是没必要的
于是 我把代码修改为
db.Instructors .Include(i => i.OfficeAssignment) .Include(i => i.Courses) .OrderBy(i => i.LastName);
去掉了对院系的贪婪加载
看下生成的SQL语句
SELECT [Project1].[InstructorID1] AS [InstructorID], [Project1].[InstructorID] AS [InstructorID1], [Project1].[LastName] AS [LastName], [Project1].[FirstName] AS [FirstName], [Project1].[HireDate] AS [HireDate], [Project1].[InstructorID2] AS [InstructorID2], [Project1].[Location] AS [Location], [Project1].[C1] AS [C1], [Project1].[CourseID] AS [CourseID], [Project1].[Title] AS [Title], [Project1].[Credits] AS [Credits], [Project1].[DepartmentID] AS [DepartmentID] FROM ( SELECT [Extent1].[InstructorID] AS [InstructorID], [Extent1].[LastName] AS [LastName], [Extent1].[FirstName] AS [FirstName], [Extent1].[HireDate] AS [HireDate], [Extent2].[InstructorID] AS [InstructorID1], [Extent3].[InstructorID] AS [InstructorID2], [Extent3].[Location] AS [Location], [Join3].[CourseID1] AS [CourseID], [Join3].[Title] AS [Title], [Join3].[Credits] AS [Credits], [Join3].[DepartmentID] AS [DepartmentID], CASE WHEN ([Join3].[CourseID2] IS NULL) THEN CAST(NULL AS int) ELSE 1 END AS [C1] FROM [dbo].[Instructor] AS [Extent1] LEFT OUTER JOIN [dbo].[OfficeAssignment] AS [Extent2] ON [Extent1].[InstructorID] = [Extent2].[InstructorID] LEFT OUTER JOIN [dbo].[OfficeAssignment] AS [Extent3] ON [Extent2].[InstructorID] = [Extent3].[InstructorID] LEFT OUTER JOIN (SELECT [Extent4].[CourseID] AS [CourseID2], [Extent4].[InstructorID] AS [InstructorID], [Extent5].[CourseID] AS [CourseID1], [Extent5].[Title] AS [Title], [Extent5].[Credits] AS [Credits], [Extent5].[DepartmentID] AS [DepartmentID] FROM [dbo].[CourseInstructor] AS [Extent4] INNER JOIN [dbo].[Course] AS [Extent5] ON [Extent5].[CourseID] = [Extent4].[CourseID] ) AS [Join3] ON [Extent1].[InstructorID] = [Join3].[InstructorID] ) AS [Project1] ORDER BY [Project1].[LastName] ASC, [Project1].[InstructorID1] ASC, [Project1].[InstructorID] ASC, [Project1].[InstructorID2] ASC, [Project1].[C1] ASC
继续分析
if (id != null) { ViewBag.InstructorID = id.Value; viewModel.Courses = viewModel.Instructors.Where(i => i.InstructorID == id.Value).Single().Courses; }
如果点击教师 则可查看该教师教的课程 这个id 就是教师ID 一会儿会在视图展示这个 这个就是根据教师查看课程
接着是点击课程 查看所选的学生和分数
if (courseId != null) { viewModel.Enrollments = viewModel.Courses.Where(i => i.CourseID == courseId.Value).Single().Enrollments; }
这里还给出里另一种方法
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 = viewModel.Courses.Where(x => x.CourseID == courseID).Single().Enrollments; }
最后上视图
@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> <th>Courses</th> </tr> @foreach (var item in Model.Instructors) { string selectedRow = ""; if (item.InstructorID == ViewBag.PersonID) { 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> @String.Format("{0:d}", 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> </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> }
@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> @item.Grade </td> </tr> } </table> }
三.上节的一个问题与疑问的提出
再上节的建立关系中 有一个这样的问题 一对多的关系中 是否应该为导航属性 再专门建立一个ID
比如我们可 课程与院系 一个院系可以有多个课程 一个课程只能属于一个院系 那我们是否应该在课程类里 加入院系ID呢
如
/// <summary> /// 课程类 /// </summary> public class Course { /// <summary> /// 课程ID /// </summary> [DatabaseGenerated(DatabaseGeneratedOption.None)] [Display(Name = "Number")] public int CourseID { get; set; } /// <summary> /// 课程名称 /// </summary> [Required(ErrorMessage = "Title is required.")] [MaxLength(50)] public string Title { get; set; } /// <summary> /// 学分 /// </summary> [Required(ErrorMessage = "Number of credits is required.")] [Range(0, 5, ErrorMessage = "Number of credits must be between 0 and 5.")] public int Credits { get; set; }
[Display(Name = "Department")] public int DepartmentID { get; set; }
/// <summary> /// 关系表导航属性 一个课程允许被多次报名等级 /// </summary> public virtual ICollection<Enrollment> Enrollments { get; set; } public virtual Department Department { get; set; } public virtual ICollection<Instructor> Instructors { get; set; }
}
这里面加了 院系ID 我以前一直觉得没有必要加这个 今天在做这个导航属性查找时 发现一个问题 做个小实验
比如我想得到其中一个课程的ID 如果有院系ID 属性 可以这么写
var courses = db.Courses.ToList(); int i = courses[0].DepartmentID;
如果没 可以这么写
int i = courses[0].Department.DepartmentID;
首先 这个都没有用贪婪加载 默认的延迟加载 如果你使用上面的 则不会往数据库里去执行一条根据课程ID查找院系的SQL语句
但你使用下面的 则会往数据库里发送一条查找语句
这点 EF做的是并不好的 在NH里 两种方法 都不会发送 因为在下面那里使用了代理 而EF没有
我想问的是 是我哪操作的不对么? 造成了这个原因? 请高手解答下
四.总结
关系的加载就结束了 其实写关系加载的园子中有不少好文章了 我这里写的少了些~~
不过关系的操作还没有结束
下一篇
导航属性的更新等操作
MVC3+EF4.1学习系列(五)----- EF查找导航属性的几种方式的更多相关文章
-
MVC3+EF4.1学习系列(七)-----EF并发的处理
看这篇文章之前 推荐园子里的 这个文章已经有介绍了 而且写的很好~~ 可以先看下他的 再看我的 并发 1.悲观并发 简单的说 就是一个用户访问一条数据时 则把这个数据变为只读属性 把该数据变为独占 ...
-
MVC3+EF4.1学习系列(四)----- ORM关系的处理
上篇文章 终于把基础的一些操作写完了 但是这些都是单表的处理 而EF做为一个ORM框架 就必须点说说对于关系的处理 处理好关系 才能灵活的运用EF 关于关系的处理 一般就是 一对一 一对多 ...
-
MVC3+EF4.1学习系列(一)-------创建EF4.1 code first的第一个实例
基于EF4.1 code first 简单的CRUD 园子中已经有很多了 ~~ 真不想再写这个了 可是为了做一个完整的小demo 从开始 到后面的一些简单重构 还是决定认真把这个写出来 争取写些别人 ...
-
MVC3+EF4.1学习系列(二)-------基础的增删改查和持久对象的生命周期变化
上篇文章中 我们已经创建了EF4.1基于code first的例子 有了数据库 并初始化了一些数据 今天这里写基础的增删改查和持久对象的生命周期变化 学习下原文先把运行好的原图贴来上~~ 一.创建 ...
-
MVC3+EF4.1学习系列(九)-----EF4.1其他的一些技巧的使用
上节通过一系列重构 简单的项目就实现了 不过还有些EF的功能没有讲 这节就通过项目 讲讲EF其他的功能与技巧 一.直接执行SQL语句 通常来讲 EF 不用写SQL语句的 但是 在有些场合 比如对生 ...
-
MVC3+EF4.1学习系列(八)-----利用Repository and Unit of Work重构项目
项目最基础的东西已经结束了,但是现在我们的项目还不健全 不利于测试 重复性代码多 层与层之间耦合性高 不利于扩展等问题.今天的这章 主要就是解决这些问题的.再解决这些问题时,自己也产生了很多疑 ...
-
MVC3+EF4.1学习系列(六)-----导航属性数据更新的处理
通过上一篇的学习 我们已经知道怎么查询关系 这篇就来说说怎么导航属性数据更新时的处理 以及EF又会为我们生成哪些SQL~ 老规矩 先看下今天的图 添加和修改页面基本就是这样 这节的内容相对简单~~ 主 ...
-
C# 数据操作系列 - 7. EF Core 导航属性配置
在上一篇,大概介绍了Entity Framework Core关于关系映射的逻辑.在上一篇中留下了EF的外键映射没有说,也就是一对一,一对多,多对一,多对多的关系等.这一篇将为大家细细分析一下,如何设 ...
-
MVC3+EF4.1学习系列(十)----MVC+EF处理树形结构
通过前几篇文章 我们处理了 一对一, 一对多,多对多关系 很好的发挥了ORM框架的做用 但是 少说了一种 树形结构的处理, 而这种树形关系 我们也经常遇到,常见的N级类别的处理, 以及经常有数据与类别 ...
随机推荐
-
Types of CQRS
Types of CQRS By Vladimir Khorikov CQRS is a pretty defined concept. Often, people say that you eith ...
-
addChildViewController
http://www.cnblogs.com/zengyou/p/3386605.html //在parent view controller 中添加 child view controller Fi ...
-
BZOJ 3999 旅游
.......好长啊. #include<iostream> #include<cstdio> #include<cstring> #include<algo ...
-
定时自动同步文件,支持多文件夹同步,支持过滤文件和文件夹,解决FileSystemWatcher多次文件触发事件(源码)
博客园里面有很多同步工具和软件,关于FileSystemWatcher类解释的也很多,但收集了很多文章后,感觉没好的方法,自己没事写了一个定时文件同步,借鉴了很多博客园朋友的东西: 上主菜: 配置文件 ...
-
Spring Boot 整合 Mybatis Annotation 注解的完整 Web 案例
摘要: 原创出处 www.bysocket.com 「泥瓦匠BYSocket 」欢迎转载,保留摘要,谢谢! 『 公司需要人.产品.业务和方向,方向又要人.产品.业务和方向,方向… 循环』 本文提纲一. ...
-
openlayers4 入门开发系列之地图模态层篇(附源码下载)
前言 openlayers4 官网的 api 文档介绍地址 openlayers4 api,里面详细的介绍 openlayers4 各个类的介绍,还有就是在线例子:openlayers4 官网在线例子 ...
-
How to Make Fibonacci Confusing
前几天同事发了这么一段代码 (fn => (f => f(f))(f => fn(n => f(f)(n))) )(g => n => [1, 2].indexOf ...
-
iOS 加锁的方式
iOS多线程编程中,经常碰到多个线程访问共同的一个资源,在线程相互交互的情况下,需要一些同步措施,来保证线程之间交互的时候是安全的.下面我们一起看一下学一下iOS的几种常用的加锁方式,希望对大家有所帮 ...
-
Python 入门基础19 --面向对象、封装
2019.04.17 一.面向对象与面向过程 二.名称空间操作 三.类与对象的概念 四.语法 五.对象查找属性的顺序 2019.04.18 1.类与对象的所有概念:__init__方法 2.类的方法与 ...
-
TCP/IP协议(1):各层协议帧格式
一. 1.OSI与TCP/IP对应: TCP/IP各层功能: 链路层:包括操作系统的设备驱动程序和计算机的网卡,提供底层传输服务. 网络层:为数据选择路由,在众多计算机和网络设备组成的网络中选择一 ...