对于任何一个ORM框架,CRUD都是其核心功能,可以这么说,CRUD功能实现得好坏,直接决定了此ORM框架的命运。

CRUD是英文Create、Read、Update、Delete四个单词的缩写,对应于汉语,就是“增、删、改、查”四个字。再细分一下,“增、删、改”可归为一类,其特点是要更新数据源,而“查”则归为另一类,它不修改原始的数据源。

我们的技术探索之旅,从“查”开始。

1 两种查询数据的方式

EF主要使用两种方式查询数据:LINQto Entities和一组针对IQueryable<T>的扩展方法。

采用LINQ方式的查询代码拥有很强的可读性:

[csharp] view plaincopyprint?
  1. using (var context = new BookDb())
  2. {
  3. var books = from book incontext.Books
  4. select new { bookName = book.Name , reviewCount = book.Reviews.Count };
  5. foreach (var book in books)
  6. {
  7. Console.WriteLine("{0}有书评{1}条。",book.bookName, book.reviewCount);
  8. }
  9. }

无需加注释,只看代码就能很轻松地知道其功能提取保存在数据库中的所有书的书评数量信息。

上述功能也可以使用扩展方法实现,这时需要编写Lambda表达式:

[csharp] view plaincopyprint?
  1. using (var  context = new BookDb())
  2. {
  3. foreach (var book incontext.Books.Select( b => new { bookName = b.Name , reviewCount = b.Reviews.Count}))
  4. {
  5. Console.WriteLine("{0}有评论{1}条。",book.bookName, book.reviewCount);
  6. }
  7. }

这两种方式没有好坏之分,只不过使用第二种方式可能会让别人觉得你“比较牛B”。  :-)

2 装入相关联的数据

大多数数据实体间都有着各种各样的关联,最常见的是比如一本书关联多个书评,这是一对多的关联。而书与书的作者之间的关系,就是多对多关联:一个作者可以写多本书,一本书作者也可以不止一个。

EF在数据实体间建立导航属性实现关联。在实际项目中,经常是得到一个(或一堆)实体对象之后,需要查询相关联的“另一堆”对象所封装的信息,这就是“关联数据的装入”问题。

对于这个问题,EF支持三种装入策略。

(1)当导航属性是virtual时,EF默认使用“延迟装入(lazy loading)”。比如书与书评的关联定义如下:

[csharp] view plaincopyprint?
  1. public class Book
  2. {
  3. ……
  4. public virtual List<BookReview> Reviews { get; set; }
  5. }

则仅当程序中需要访问某Book对象的Reviews属性时,EF才向数据库发出SQL命令装入相关的书评数据。

(2)如果确认与某实体对象相关联的数据是确实需要的,可以使用Include()方法通知EF这个情况,EF将告诉数据库:“把XXX和XXX打包,一次性地发给我”:

[csharp] view plaincopyprint?
  1. var  books = from book in context.Books.Include("Reviews")
  2. select book;
  3. foreach (var  book in books)
  4. {
  5. Console.WriteLine ("{0}有评论{1}条。", book.Name , book.Reviews.Count);
  6. }

这种方式称为“预先装入(Eager Loading)”。避免了第2次访问数据库的需要。

(3)第三种方式称为“显式装入(Explicit Loading)”,使用Load()方法实现,例如,以下代码让EF装入50条书和书评信息到内存中:

[csharp] view plaincopyprint?
  1. context.Books.Take(50).Include("Reviews").Load();

这些数据“就位”后,可以缓存起来备用。

我们也可以“有目的”地只提取需要的数据,请看以下代码:

[csharp] view plaincopyprint?
  1. using (var context = new BookDb())
  2. {
  3. Book book =context.Books.First();
  4. context.Entry(book).Collection("Reviews").Load();
  5. Console.WriteLine("{0}有书评{1}条。",book.Name, book.Reviews.Count);
  6. }

上述代码将只提取第一本书的所有书评。

下面对这三种模式进行一个小结:

(1)就查询性能而言,是“预先装入(Eager Loading)”最好,因为数据己全部装入内存,后继的查询无需再访问数据库。其缺点是可能会占用大量的内存。

(2)如果能预知要访问的数据项,并且当前在内存的数据对象中,只有少数对象需要查询获取更进一步的数据,那么使用“显式装入(Explicit Loading)”策略能有效地减少数据传输量,获得较高的性能。

(3)当一个实体类拥有多个一对多的关联,而且难以预知要访问的数据项,则“延迟装入(Lazy Loading)”又比较合适了,它仅在“需要用到时”才提取数据,能有效地减少内存占用,但可能给数据库服务器带来过多的数据查询请求。

(4)当数据实体对象需要序列化时,一定要使用“预先装入(Eager Loading)”,其原因是序列化对象时需要使用反射查询数据实体对象的所有属性,如果是延迟装入(Lazy Loading)”,将会导致向数据库发出大量的查询请求,而且每个对象都要发出“一堆”这样的查询请求,绝对会让数据库痛苦!

3 Find方法与本地数据

DbSet有一个Local属性很有趣,它引用当前己装入内存的数据,注意它包括当前己从数据库中取出或新加的但还没有保存到数据库中的数据,我们可把它称为DbSet对象的“本地数据集合”。

本地数据集合的一个重要特性是:针对它发出的各种查询不会发往数据库。

请看以下场景:

假设我只想提取数据库中第1本和第11本书的书评信息,以下代码完成这一工作:

[csharp] view plaincopyprint?
  1. using (var context = new BookDb())
  2. {
  3. Book book =context.Books.First();
  4. Console.WriteLine("{0}有书评{1}条。",book.Name, book.Reviews.Count);
  5. book =context.Books.OrderBy(b => b.BookId).Skip(10).First();
  6. Console.WriteLine("{0}有书评{1}条。",book.Name, book.Reviews.Count);
  7. }

打开SQL Server Profiler,你会发现EF先后为上述代码生成了4条SQL命令发给数据库。

现在修改一下代码,使用 “显式装入”+ Local查询 方式:

[csharp] view plaincopyprint?
  1. using (var context =new  BookDb())
  2. {
  3. //提前装入50条书和书评数据到内存中
  4. context.Books.Take(50).Include("Reviews").Load();
  5. //在本地集合中进行查询
  6. Book book =context.Books.Local.First();
  7. Console.WriteLine("{0}有书评{1}条。",book.Name, book.Reviews.Count);
  8. book =context.Books.Local.OrderBy(b=>b.BookId).Skip(10).First();
  9. Console.WriteLine("{0}有书评{1}条。",book.Name, book.Reviews.Count);
  10. }

查看一下SQL ServerProfiler,你会发现EF只为上述代码生成一条SQL命令(虽然这条命令比较复杂,但毕竟只有一条)发给数据库,后继的查询都是在内存中进行的,相当地快!

“本地数据集合”还有另一个值得关注的特性。

请注意DbSet.Local属性的类型是ObservableCollection,当向DbSet中添加和移除数据时,此“本地数据集合”对象会激发CollectionChanged事件。这对于WPF桌面应用来说实在是太妙了!

你可以在WPF桌面程序中这样干:

使用DbContext提取数据后,让WPF数据绑定控件(比如DataGrid)通过ViewSource组件绑定到相应DbSet的Local属性,之后就可以在窗体上进行CRUD操作,所有操作被DbContext缓存起来,当用户点击“保存”按钮(或者是关闭窗体时),调用DbContext.saveChanges()方法存入数据库。DbContext会自动跟踪实体对象的状态,整个过程完全是自动化的!

如果你基于.NET 4.5并使用EF 6,则可以在WPF应用中直接使用EF6新增的异步方法,比如DbContext.SaveChangesAsync(),EF会在独立的线程中完成数据的提取、保存等工作(线程的分派工作在底层由.NET的TPL负责,程序员可以不理会它),并且在这些工作结束时,异步方法的后继代码将在UI线程中执行,这样一来,多线程应用中原来比较讨厌的跨线程更新UI控件的问题就不存在了,用起来实在是方便,代码可以精简不少!

最后一个“本地数据集合”相关联的话题是DbSet的Find方法,开发时记住以下这句话就行了:

使用Find方法查询数据时,它会先在内存中找,找不到之后再到数据库中提取。

有关数据查询的技巧还有不少,本篇文章只是介绍了我觉得比较重要的知识和比较有用的一些技巧,算是抛砖引玉吧。

下篇文章带领大家到EF“更新数据”这个领域“寻幽探胜”。

来源: <http://blog.csdn.net/bitfan/article/details/13001935>
来自为知笔记(Wiz)

转载于:https://www.cnblogs.com/liyanwei/p/d9f9b690e71b14bcaf765a92b442e8e9.html

EntityFramework走马观花之CRUD(上)相关推荐

  1. [转]EntityFramework走马观花之CRUD(中)

    学习Entity Framework技术期间查阅的优秀文章,出于以后方便查阅的缘故,转载至Blog,可查阅原文:http://blog.csdn.net/bitfan/article/details/ ...

  2. java9.0.4配置_Tomcat 9.0 安装配置

    本文转自:http://blog.sina.com.cn/s/blog_15126e2170102w5o8.html 一.JDK的安装与配置 1.从官网下载jdk,注意是jdk不是jre.最好从官网下 ...

  3. 学海泛舟系列文章开篇语

    书山有路勤为径,学海无涯苦作舟                      --学海泛舟系列文章开篇语             金旭亮 我大约是在1994年前后开始系统学习计算机技术的,到目前为止,己接 ...

  4. 如何优雅的使用DbContext

    转载自:http://blog.csdn.net/bitfan/article/details/14231561 EntityFramework走马观花之 CRUD(下) 我在Entity Frame ...

  5. ADO.NET与ORM的比较(5):MyBatis实现CRUD

    说明:这是一个系列文章,在前面的四篇当中周公分别讲述了利用ADO.NET.NHibernate.Linq to SQL及EntityFramework来实现CRUD功能(C:Create/R:Read ...

  6. mybatis.net mysql_ADO.NET与ORM的比较(5):MyBatis实现CRUD

    说明:这是一个系列文章,在前面的四篇当中周公分别讲述了利用ADO.NET.NHibernate.Linq to SQL及EntityFramework来实现CRUD功能(C:Create/R:Read ...

  7. EntityFramework之领域驱动设计实践(十)(转)

    http://www.cnblogs.com/daxnet/archive/2010/07/19/1780764.html 规约(Specification)模式 本来针对规约模式的讨论,我并没有想将 ...

  8. 基于 EntityFramework 的数据库主从读写分离架构(1) - 原理概述和基本功能实现...

    回到目录,完整代码请查看(https://github.com/cjw0511/NDF.Infrastructure)中的目录: src\ NDF.Data.EntityFramework\Maste ...

  9. EntityFramework Core 2.0执行原始查询如何防止SQL注入?

    前言 接下来一段时间我们来讲讲EntityFramework Core基础,精简的内容,深入浅出,希望为想学习EntityFramework Core的童鞋提供一点帮助. EntityFramewor ...

最新文章

  1. Statement接口实现查询数据、添加数据
  2. tomcat安装_基于CentOS 一键安装tomcat脚本
  3. 解决TreeView中使用JavaScript完成CheckBox全选的办法
  4. C#中重写(override)和覆盖(new)的区别
  5. 【Java】接口(interface)VS抽象类
  6. linux服务器防端口扫描,linux下防止syn***,端口扫描和死亡之ping
  7. 前端 IndexDB 操作入门教程
  8. 程序员如何实现编码黄金标准?
  9. html最大化和最小化,电脑上最大化最小化图标变了怎么办
  10. 北斗导航 | RAIM算法流程图
  11. 如何成功安装旧版本火狐,成功安装firebug和firepath插件
  12. python3的字符串操作
  13. Wilcoxon符号秩+秩和检验学习[转载]
  14. 如何设置word 中endnote的引用格式:作者(年份)
  15. java 围棋_围棋冠军都输了?用Java编写的智能围棋战力惊人?
  16. python视频转化_python实现视频读取和转化图片
  17. 微信小程序(五)新版的用户授权和判断是否是否已经授权和自动提示更新版本
  18. [渝粤教育] 长安大学 互换性与技术测量 参考 资料
  19. ardruino控制继电器_Arduino基础入门篇24—继电器控制
  20. 三星s9更新android9.0 体验,国行三星Galaxy S9系列更新Android 9.0 界面更漂亮

热门文章

  1. centos linux引导修复_【Linux 运维】 Centos7.x 系统修复模式
  2. Linux学习笔记-grep的基本认识
  3. android cpu负载 工具,计算Android中进程的CPU使用率
  4. ubuntu 20.04 快速开启TCP BBR实现高效单边加速
  5. java读取文件夹,如何从Java读取文件夹中的所有文件?
  6. shell中修改=后的值
  7. 图解extends and implements 的区别
  8. LeetCode:892. 三维形体的表面积
  9. (软件工程复习核心重点)第六章实现和测试-第二节:软件测试基础
  10. (计算机组成原理)第三章存储系统-第三节2:ROM芯片