MVC3+EF4.1学习系列(五)----- EF查找导航属性的几种方式

通过上一篇的学习 我们把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语句

继续分析

  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 @:&nbsp; @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呢

课程类

这里面加了 院系ID  我以前一直觉得没有必要加这个 今天在做这个导航属性查找时 发现一个问题 做个小实验

比如我想得到其中一个课程的ID 如果有院系ID 属性 可以这么写

   var courses = db.Courses.ToList();      int i = courses[0].DepartmentID;

如果没 可以这么写

 int i = courses[0].Department.DepartmentID;

首先 这个都没有用贪婪加载 默认的延迟加载 如果你使用上面的 则不会往数据库里去执行一条根据课程ID查找院系的SQL语句

但你使用下面的 则会往数据库里发送一条查找语句

这点 EF做的是并不好的 在NH里 两种方法 都不会发送  因为在下面那里使用了代理 而EF没有

我想问的是 是我哪操作的不对么? 造成了这个原因? 请高手解答下

四.总结

关系的加载就结束了 其实写关系加载的园子中有不少好文章了 我这里写的少了些~~

不过关系的操作还没有结束

时间: 2024-08-10 05:55:54

MVC3+EF4.1学习系列(五)----- EF查找导航属性的几种方式的相关文章

MVC3+EF4.1学习系列(七)-----EF并发的处理

看这篇文章之前 推荐园子里的 这个文章已经有介绍了 而且写的很好~~ 可以先看下他的 再看我的 并发 1.悲观并发 简单的说 就是一个用户访问一条数据时 则把这个数据变为只读属性  把该数据变为独占 只有该用户释放了这条数据 其他用户才能修改 这期间如果该用户上个厕所 出去玩一圈 没有退出 则其他人都要等很久 很显然 这不是我们期望的效果  也不是这篇文章讨论的重点 2.乐观并发 乐观并发相对悲观并发,用户读取数据时不锁定数据.当一个用户更新数据时,系统将进行检查,查看该用户读取数据后其他用户是

MVC3+EF4.1学习系列(二)-------基础的增删改查和持久对象的生命周期变化

上篇文章中 我们已经创建了EF4.1基于code first的例子  有了数据库 并初始化了一些数据  今天这里写基础的增删改查和持久对象的生命周期变化 学习下原文先把运行好的原图贴来上~~ 一.创建详细页 首先 我们先在控制器下 添加详细页的方法 因为这篇文章后面要介绍持久对象声明周期的变化 所以在这里先看下有哪些状态 EF里一共有这五中生命状态类型 其实 看名字我们可以大概猜测出个一二三来~~  游离的 未改变的  新添加的  已删除的 修改的  但是是怎么变化的能 我们在后面的代码中实践与

MVC3+EF4.1学习系列(一)-------创建EF4.1 code first的第一个实例

基于EF4.1 code first 简单的CRUD  园子中已经有很多了 ~~ 真不想再写这个了 可是为了做一个完整的小demo 从开始 到后面的一些简单重构 还是决定认真把这个写出来 争取写些别人没写到的东西~~ 好了 开始~~ 这次要做的是个学校管理的demo(通俗些) 先建一个MVC3的应用程序  因为我们是code first 所以 开始创建实体类 一.创建Model 学生和学生成绩登记表是一对多的关系  一个学生可以有多次登记 (因为有多个课程)  一个课程也可以有多个登记   可以

MVC3+EF4.1学习系列(九)-----EF4.1其他的一些技巧的使用

上节通过一系列重构 简单的项目就实现了 不过还有些EF的功能没有讲 这节就通过项目 讲讲EF其他的功能与技巧 一.直接执行SQL语句 通常来讲 EF 不用写SQL语句的  但是 在有些场合  比如对生成的SQL语句 觉得不满意 要做优化  或者做报表统计时 要写很变态的SQL语句 再或者 批量操作等   这个时候 使用ORM的弱点就显露了出来 但是 做为优秀的ORM框架  EF 是支持原生态的SQL的   这里面 提供了三种方法 1. DbSet.SqlQuery   有跟踪状态的查询  2. 

MVC3+EF4.1学习系列(八)-----利用Repository and Unit of Work重构项目

项目最基础的东西已经结束了,但是现在我们的项目还不健全  不利于测试 重复性代码多   层与层之间耦合性高  不利于扩展等问题.今天的这章 主要就是解决这些问题的.再解决这些问题时,自己也产生了很多疑问,理解的也并不是很透彻 ,希望我的疑问能在这里得到解答~~ 一.模式介绍 1.Repository 在<企业架构模式>中,通过用来访问领域对象的一个类似集合的接口,在领域与数据映射层之间进行协调.还有请大家参考这个  P OF EAA详细介绍 然后说下我对这个的感觉和疑问   怎么都觉得这个Re

MVC3+EF4.1学习系列(十)----MVC+EF处理树形结构

通过前几篇文章 我们处理了 一对一, 一对多,多对多关系 很好的发挥了ORM框架的做用 但是 少说了一种 树形结构的处理, 而这种树形关系 我们也经常遇到,常见的N级类别的处理, 以及经常有数据与类别挂钩.今天主要写下EF处理树形结构以及 MVC如何展示树形结构. 前面几篇的例子 一直用的是一个例子,内容是连贯的.这篇是完全单独的~ 先来说下工作中会遇到的常见场景 针对这几个场景来处理~ 1.类别 a.类别可以有无限级别 b.类别的最末端 不确定是第几级 某个节点 可以到二级 其他的节点 有可能

MVC3+EF4.1学习系列(十一)----EF4.1常见的问题解决

博客写了10篇了~有很多朋友私信问了一些问题,而且很多问题 大家问的都一样 这里说说这些常见问题的解决办法.如果大家有更好的解决办法~也希望分享出来 问题大概为这几个 一.ef4.1 codeFirst 修改表结构 增加字段等 EF code first需要重新生成库导致数据丢失的问题. 二.ef4.1 没有了edmx等复杂的东西 变得简单 干净  但如何使用存储过程,存储过程可以返回表 可以返回数值 也有可能是执行修改 删除 增加等  该怎么做? 三.ef4.1 如何使用数据库视图?每个视图都

javascript基础学习系列-DOM盒子模型常用属性

最近在学习DOM盒子模型,各种属性看着眼花缭乱,下面根据三个系列来分别介绍一下: client系列 clientWidth :width+(padding-left)+(padding-right)->和内容溢出无关系 clientHeight:height+(padding-top)+(padding-bottom)->和内容溢出无关系 clientLeft:左边框的宽度 clientTop:上边框的高度(border[Left/Top]Width) offset系列 offsetParen

Cocos2d-x学习笔记(五岁以下儿童) 精灵两种方式播放动画

 这几天在看控件类,临时没有想好实际运用的方向.单纯的创建网上已经有非常多这方面的样例,我就不写了.接下来是学习精灵类.精灵类若是单独学习也是非常easy.于是我加了一些有关动画方面的知识点与精灵类一起使用.让精灵播放简单的帧动画. 首先我们准备好动画素材,我在网上下了一个小游戏.将里面的素材做成了png和plist大图以供程序调用.我是用TexturePackerGUI来生成plist的.我选的是一个简单的待机动作,我们的目的就是让这张图动起来~ 第一种方式:使用CCSpriteFrame