EF中LINQ查询原理

   2     在接触Linq以前,一直据说Linq被微软抛弃。后来才发现被抛弃的是Linq to SQL这种专用于操做Sql Server的轻型ORM,微软宣布中止更新Linq to Sql,把开发的重点从 Linq to SQL 转移到了 Linq to Entities数据库

在EF中使用Linq查询数据的基本形式是这样的:ide

<span style="font-size:14px;"><pre name="code" class="csharp">var  result = from  t in Table
where  t.id > 10
select  t;</span>

 
这个形式在Linq  to 各类都是通用的,下面讲一下它的原理。 

        不少人都觉得,上面的语句执行事后就完成了查询操做,把查询的结果载入了result中,然而事实是上面的语句只完成了一个result对象的建立和初始化。事实上真正的查询是在foreach语句开始时发生的,查询到的数据载入,而后再遍历取数据。你能够尝试在Sql Server的profile工具中监控一下,上面的语句执行完成,数据库并无监控到任何信息,当你尝试在"result“中拿数据的时候,profile工具监测到了数据库访问,这也就是延时加载,若是你想关闭延时加载能够在EF模型的属性中设置。函数

        这里的result的类型实际上是DbQuery,它有实现一个接口IQueryable<>,IQueryable<>是Linq命名空间下的一个特有的集合,它的类型参数是实体类或其父类,或者不用泛型,默认的是Object,这涉及到协变。因为采用了延时加载,因此说这是一种离线集合。也就是说你尝试在"result"中取一次数据,它就会去数据库查询一次,因此若是须要持续使用某些数据,应该是手动建立对象,存入本地内存中。工具

        那么Linq查询的原理和IQueryable<>有什么关系呢?其实在IQueryable<>中仅有三个属性:spa

Type ElementTypecode

Expression Expression对象

IQueryProvider Provider接口

        

        咱们在写Linq表达式并完成IQueryable<>对象建立的时候,它的初始化过程是这样的:声明元素类型,这一点从属性名字就能够看出来,而后创建Expression对象,这里就是把你写的Linq表达式进行解析,拆分,解析成一个表达式树,也就是对Lambda表达式的解析过程,Expression对象以二叉树结构存储解析结果。最后根据LINQ表达式类型给IQueryableProvider provider属性赋值。 在你须要读取数据的时候Provider属性就去解析Expression表达式树执行查询返回。因此这就作到了无论你是Linq to Sql仍是Linq  to Entities,都能使用。内存

       

        其实EF跨数据库的核心也在这里,目前多个数据库厂商开始逐渐支持EF,他们只须要作一个工做,那就是写对应数据库的Provider驱动便可,你能够在本身的项目中引用不一样数据库的Provider,而后更改链接字符串的providerName属性就完成了跨数据库操做。开发

        有时候咱们能够直接把Linq的查询结果载入本地集合,也就是List,Array这样,存入内存中。Linq表达式能够这样写:

<span style="font-size:14px;">var  result = from  t in Table.ToList()
where  t.id > 10
select  t;</span>
        这时候查询就变成了Linq to Object,上面不一样,在这条语句执行完成事后,数据就已经从数据库中查询,载入内存,变成了Object。因此这里的全部操做都是在内存中进行,若是不适用ToList()函数,最后执行的SQL语句中加入了Linq表达式中的where条件,而这种方法则是将数据所有载入内存,在内存中使用where的筛选条件过滤。