Loading

LINQ IN ACTION读书笔记:在运行时创建查询——表达式树

动态查询语句:之所以叫做动态查询语句是因为语句中使用的某些值,甚至之句将在运行时而不是编译时才能被最终决定。在编写查询语句时,还不能得到执行查询所需要的信息,因为这些信息可能会来自用户输入或者程序运行时的上下文,甚至在一些更高级的应用中,我们可能需要在程序运行时从无到有地完整创建出一个查询。比如,若应用程序需要查询来自多种地方的数据,例如XML文件、远程应用程序或用户等。我们可以使用最终的武器——表达式树。

 

例如:如下XML片段描述将要应用到某个图书集合上的过滤条件。

<and>
	<notEqual property="Title" value="Bonjour mon Amour"/>
	<greaterThan property="pageCount" value="200"/>
</and>

如果直接编写这个查询,则如下:

var q = from book in SampleData.Books
        where (book.Title != "Bonjour mon Amour" && book.PageCount > 200)
        select book;

这个查询完全定义于编译期,不过若是该XML文件在运行时才交付给程序,那么就不可能按照这种写法书写,因为程序已经编译过了,此时的解决方案就是使用表达式树.

创建表达式树的最简单的方法就是让编译器将Expression<TDelegate>类型的Lambda表达式转换成一系列的工厂方法调用,然后借助这些工厂方法在运行时创建表达式树。不过若是为了生成动态查询语句,那么则要以另外的方法创建表达式树。我们完全可以根据需要自行调用这些工厂方法(即一系列定义于Expression<TDelegate>类中的静态方法)来创建出表达式树,并在运行时将其编译成Lambda表达式。

var book = Expression.Parameter(typeof (Book), "book");
var titleExpression = Expression.NotEqual(Expression.Property(book, "Title"),
                                          Expression.Constant("Bonjour mon Amour"));
var pageCountExpression = Expression.GreaterThan(Expression.Property(book, "PageCount"), Expression.Constant(200));
var andExpression = Expression.And(titleExpression, pageCountExpression);
var predicate = Expression.Lambda(andExpression, book);
var query = Enumerable.Where(SampleData.Books, (Func<Book, bool>) predicate.Compile());
GridView1.DataSource = query.ToList();
GridView1.DataBind();

以上从无到有创建出了一个查询表达式,用来实现XML中描述的需求。对该表达式树的每个增强操作都是通过向其添加新的表达式来实现的。倒数第三四代码将该表达式树转换为能够执行的查询语句。其中query变量的使用方法与其他的LINQ查询语句相比没有什么区别。

 

LINQ IN ACTION  @2012-3-15 23:20:33

posted @ 2012-03-15 23:21  Dhoopu  阅读(602)  评论(0编辑  收藏  举报