第5讲:查询表达式LINQ(3)

2007.8.9 李建忠

Linq查询执行过程

image

注意,result变量仅仅是对Linq查询的一个描述,而非执行结果。换言之,Linq查询语句并不立即执行得到结果,而是将查询缓存在变量result中。

那么result的类型是什么呢?IQueryable<Product>

 

IQueryable<T>类型

image

image

image

通过IL代码可以看出,result执行foreach的时候,才调用了GetEnumerator方法,因为result就是IQueryable<Product>类型。

 

Linq执行与IQueryable<T>接口

image

IQueryable<T>只是查询表示,类似于SqlCommand等命令表示,真正的查询执行要依赖于在其上的调用操作。只不过SqlCommand表达查询的是一个查询字符串,而IQueryable<T>表达查询的是一个Expression强类型数据结构。

foreach语句会导致IQueryable<T>上的方法GetEnumerator()执行,从而导致查询的执行,并将返回结果IEnumerator<T>。

执行foreach的时候,实际上是执行了下面的代码:

image

这个过程中只有GetEnumerator方法的执行导致了查询的执行。

 

Linq延迟执行

image

因此,对于上述程序,两个foreach语句块会导致查询被执行两次,这种行为被称作Linq延迟执行。如果使用不当,会导致各种程序效率问题,比如大量的数据绑定如果都做的是Linq延迟执行,程序效率将会大大降低。因为每次页面重绘都需要重新查询数据库进行绑定。

 

改进Linq延迟执行

image

通过调用ToList或者ToArray方法,可以直接执行Linq查询,将查询结果缓存在list变量中。从而可以避免Linq延迟执行的效率问题。

 

更多Linq延迟执行

从数据库里面是同一行的数据,在Linq里面是不是同一个对象?

C#中表示对象相等是对象引用相等,而数据库中判断相等是根据数据行的主键是否相等。

我们下面将对同一个表做两次查询,判断两次查询的对象是不是同一个对象,来回答这个问题。

image

两次查询分别得到p1和p2两个对象,而查询的结果都是对应数据库中的同一行。

image

返回True表示p1和p2引用相等,是两个一模一样的对象。

也就是说,数据库中主键是同一行,在Linq中的两次查询也是两个地址相同的对象。这就是因为Linq的DataContext在背后做了特殊的设计,每个对象映射的是数据库的一行,如果数据库中某一行的键值曾经被查询过,那么数据库背后会做一个HashTable的结构,FI-01的键值对应地址p1,如果下次键值又找到FI-01的键值的话,那么会把p1的地址原封不动地拿出来,因此p1和p2才会相同。这样能极大提升Linq的性能,避免不必要的性能浪费。

2010.11.13

posted @ 2010-11-13 17:53  山天大畜  阅读(791)  评论(0编辑  收藏  举报