如果你还没有接触过或者根本不了解什么是Entity Framework,那么请看这里http://www.entityframeworktutorial.net/EntityFramework-Architecture.aspx,其中的一系列文章以非常简单易懂的形式一步步介绍了Entity Framework的一些基本概念和操作方法。一句话,Entity Framework是微软新的数据操作框架,在项目中引入Entity Framework可以极大的方便开发人员完成程序与数据库的各种操作。在早期的.NET应用程序中,我们直接通过SqlConnection,SqlDataAdapter,DataReader等一些基本对象来实现与数据库的操作,与数据库的每一次交互都需要专门编写大量的代码。为了将程序员的精力从这些看似无聊的代码中释放出来,让更多的人去关注程序业务方面的操作,后来出现了各种与数据库交互的类库,有一些是开源的,也有一些是程序员自己编写的通用类库。这里面比较著名的有NHibernate.NET——一个基于Mapping的关系型数据库框架。NHibernate功能强大,不过由于配置起来稍微有点复杂并且缺少默认的VS代码生成工具,在快速小型项目中往往难以得心应手。Entity Framework (以下简称EF)的出现从根本上解决了这一问题,使得程序员可以彻底从与数据库交互的底层代码中释放出来,与数据库的交互变得前所未有的简单。
使用EF在与关系型数据库的交互中不可避免地需要加载数据,如何加载数据变得至关重要。你可以设想在一个包含数十万条数据的表中,你如何通过EF来加载数据呢?一次性将所有数据载入服务器内存或者在循环中一遍又一遍地分步加载数据?使用什么样的数据加载方式需要具体问题具体分析,我们不能在这里笼统地下决定说哪种方式好哪种方式不好。但有一点是需要遵循的,那就是如何提高数据加载的效率。EF提供了几种不同的数据加载方式,我们可以根据不同的需要灵活使用它们。
先简单说一下如何创建环境。如果你对这些步骤了如指掌,请直接跳过。
1. 在Visual Studio中创建一个示例工程。最简单的莫过于ConsoleApplication
2. 在工程中添加ADO.NET Entity Data Model。如下图所示,
选择其中的两个表作为示例,表Teacher和表Course,关系如下,
添加edmx之后,Visual Studio为自动帮我们生成/添加所有需要的文件和内容,然后我们就可以开始在代码中操作数据库了。来看看在EF中几种不同的数据加载方式。
惰性加载(Lazy Loading)
默认情况下,EF会使用惰性加载方式加载数据,即ctx.Configuration.LazyLoadingEnabled = true; 在下面的代码中,外层循环会执行一次查询,并将返回的结果存放在变量q中。而内层循环会在每一次循环过程中独立进行查询,所以,如果数据库表Teacher中有100条记录而Course有1000条记录,那么整个过程将产生1001次查询。
using (var ctx = new SchoolDBEntities())
{
var q = from t in ctx.Teachers
select t; foreach (var teacher in q)
{
Console.WriteLine("Teacher : {0}", teacher.TeacherName);
Console.WriteLine("Respective Courses..."); foreach (var course in teacher.Courses)
{
Console.WriteLine("Course name : {0}", course.CourseName);
} Console.WriteLine();
Console.ReadKey();
}
}
下面是程序执行的结果以及在SQL Server Profiler中的跟踪记录。可以清楚地看到,对表Teacher只进行了一次查询,由于该表只有8条记录,于是在内层循环中又分别产生了8次对表Course的查询。
在某些场合下,这种情况是可以接受的。你完全可以根据需要来控制内层循环何时显示加载数据,或者根本不加载数据。但是,在分层结构的应用程序中,上述代码结构并不适用,因为内层循环需要依赖于外层的Context,也就是说它们是在同一个数据库上下文中完成的,如果尝试将内层循环的代码移到外面或者其它类中,则它将获取不到任何数据。
显式加载(Explicit Loading)
如果你想人为控制惰性加载的行为,可以尝试使用下面的代码。首先需要手动关闭EF的惰性加载,通过代码ctx.Configuration.LazyLoadingEnabled = false;来完成。
using (var ctx = new SchoolDBEntities())
{
ctx.Configuration.LazyLoadingEnabled = false; var q = from t in ctx.Teachers
select t; foreach (var teacher in q)
{
Console.WriteLine("Teacher : {0}", teacher.TeacherName);
Console.WriteLine("Respective Courses..."); // Conditionally load the child data
if (true)
{
ctx.Entry(teacher).Collection(c => c.Courses).Load();
} foreach (var course in teacher.Courses)
{
Console.WriteLine("Course name : {0}", course.CourseName);
} Console.WriteLine();
Console.ReadKey();
}
}
注意内层循环只有在上面高亮显示部分的代码执行之后才会获取到数据,否则返回结果为0。通过添加判断条件,我们可以对数据加载方式进行控制,从而有效地减少程序与数据库交互的次数。大多数情况下,我们从数据库获取到的数据并不都是有用的,如果每次只有很少一部分数据有用,那么我们为什么不过滤掉那些无用的数据从而尽量较少数据交互的次数呢?
预先加载(Eager Loading)
如果你想让所有数据一次性全部加载到内存中,那么你需要使用.Include(Entity)方法。看下面的代码,
using (var ctx = new SchoolDBEntities())
{
var q = from t in ctx.Teachers.Include("Courses")
select t; foreach (var teacher in q)
{
Console.WriteLine("Teacher : {0}", teacher.TeacherName);
Console.WriteLine("Respective Courses..."); foreach (var course in teacher.Courses)
{
Console.WriteLine("Course name : {0}", course.CourseName);
} Console.WriteLine();
Console.ReadKey();
}
}
如果你查看SQl Server Profiler中的跟踪信息,你会发现只有一次数据交互过程,即程序只通过一次查询便获取到了所有需要的数据。在分层结构中,该方法是最容易的,我们可以将数据库底层获取到的结果返回给上层,它不具有任何依赖项。同时,它也可以减少程序与数据库的交互次数。不过仍然有缺点,那就是如果数据量较大,一次性将所有数据载入内存往往并不是最明智的选择。.Include(Entity)方法允许级联使用,你可以预先加载具有多层级结构的数据。
就像前面所说,选择什么样的数据加载方式需要因时而异,每一种数据加载方式都有它存在的意义,但目的只有一个,那就是以最少的代价获取到需要的数据。
相关文章:Loading Related Objects (Entity Framework)
浅谈Entity Framework中的数据加载方式的更多相关文章
-
Entity Framework 4.1 : 贪婪加载和延迟加载
这篇文章将讨论查询结果的加载控制. EF4.1 允许控制对象之间的关系,当我们进行查询的时候,哪些关系的数据将会被加载到内存呢?所有相关的对象都需要吗?在一些场合可能有意义,例如,当查询的实体仅仅拥有 ...
-
浅谈WPF本质中的数据和行为
WPF缩写为Windows Presentation Foundation的缩写,本文所要谈的就是WPF本质中的数据和行为,希望通过本文能对大家了解WPF本质有所帮助. 如果自己来做一个UI框架,我们 ...
-
Entity Framework Core导航属性加载问题
前言 今天下午在开发的时候发现EF Core实体模型中的导航属性为 null,经排查既不是没有加 virtual 关键字,也不是外键关系映射错误. 解决方法 通过查询官网文档,发现,原因在于EF Co ...
-
浅谈网络爬虫爬js动态加载网页(三)
上一篇讨论了web driver对动态网页的抓取与分析,可以很清楚的看出这是一种集中式处理方式,简单说,就是利用服务器,打开一个真正的brower,然后将需要解析的地址交给浏览器,浏览器去解析,然后将 ...
-
浅谈网络爬虫爬js动态加载网页(二)
没错,最后我还是使用了Selenium,去实现上一篇我所说的问题,别的没有试,只试了一下firefox的引擎,总体效果对我来说还是可以接受的. 继续昨天的话题,既然要实现上篇所说的问题,那么就需要一个 ...
-
知识共享图文直播---(一)将数据库中的数据加载到MSFlexGrid空间中再导入Excel
熟话说万物皆有其存在的道理,为什么我突然想写<知识共享图文直播>这个系列呢?首先,我想的是记录自己学习的历程,在记录中加深自己对知识的理解,同时也希望自己的博文能帮助到其他数据库的初学者. ...
-
浅谈网络爬虫爬js动态加载网页(一)
由于别的项目组在做舆情的预言项目,我手头正好没有什么项目,突然心血来潮想研究一下爬虫.分析的简单原型.网上查查这方面的资料还真是多,眼睛都看花了.搜了搜对于我这种新手来说,想做一个简单的爬虫程序,所以 ...
-
asp.net中UpdatePanel数据加载成功后回调
//添加UpdatePanel加载成功后执行的js方法 Sys.WebForms.PageRequestManager.getInstance().add_pageLoaded(onPageLoade ...
-
bootstrap-table插件数据加载方式
data-url 直接使用data-url在table标签中定义 使用load方法加载数据 $(“#finishingTask”).bootstrapTable(‘load’,data); //dat ...
随机推荐
-
【学习笔记】python 简单创建新建一个网络客户端,并返回相关的信息
#导入socket包 import socket #使用socket.socket创建socket连接 #AF_INET表示通信类型,与IPv4对应 #SOCK_STREAM对应TCP通信 print ...
-
Adblock Plus for firefox
关于 Adblock Plus for firefox(以下简称 ABP)的一些笔记. 安装好 ABP,将如下代码保存为 html 文件,然后在 firefox 中打开: <p id=" ...
-
Ubuntu 为网卡配置静态IP地址
为网卡配置静态IP地址编辑文件/etc/network/interfaces:sudo vi /etc/network/interfaces并用下面的行来替换有关eth0的行:# The primar ...
-
bootstrap 正则表达式
<asp:TextBox runat="server" title="邮箱正确格式:xxx@xxx.xxx" class="form-cont ...
-
POJ3264 (RMQのST解法)
For the daily milking, Farmer John's N cows (1 ≤ N ≤ 50,000) always line up in the same order. One d ...
-
安卓中圆角背景图被拉伸的解决方案——.9.png
举个例子: 从网上找了一张图片 如果我们直接用这张蓝色的图来做登录按钮的背景.将这个图片设为背景以后 我们可以发现四个角全部变形了,一点也不美观.针对此问题,我们通过.9图来解决. 首先我们先了解一下 ...
-
算法与数据结构(六) 迪杰斯特拉算法的最短路径(Swift版)
上篇博客我们详细的介绍了两种经典的最小生成树的算法,本篇博客我们就来详细的讲一下最短路径的经典算法----迪杰斯特拉算法.首先我们先聊一下什么是最短路径,这个还是比较好理解的.比如我要从北京到济南,而 ...
-
犹记当年写出bug睡不着,回想今天只求睡好渡余生……
不想面对已经在博客园注册了3年多的时间 了,就是这么快的就已经过去了近3年的工作时间,从最开始的对编程的困惑到慢慢有一点的认识,好像哦就这样没有什么啊,也没有涉及到一些比较难的东西. 但是当初第一份工 ...
-
全志A33 lichee怎样编译镜像
对于全志A33 lichee编译镜像文件需要先搭建好交叉编译环境,这个搭建环境可以看之前的文档 "SINA33开发板怎样创建编译环境" 开发平台 * 芯灵思SinlinxA33开发 ...
-
学习笔记之Swagger
World's Most Popular API Framework | Swagger https://swagger.io/ Swagger is the world’s largest fram ...