[转]Dynamically Composing Expression Predicateslinq to sql的基本上规格动态查询(下)

鬼子写的一个不错的扩大表达式的章,原文地址:http://www.albahari.com/nutshell/predicatebuilder.html

凭借老外写的一个扩展表达式的类,可以把上篇中之代码写得还优雅

Dynamically Composing Expression Predicates

Suppose you wanted to write a LINQ to SQL query that implemented a
keyword-style. search. In other words, a query that returned rows whose
description contained some or all of a
given set of keywords.

We could proceed as follows:

IQueryable<Product> SearchProducts (params string[] keywords)

...{

  IQueryable<Product> query = dataContext.Products;



  foreach (string keyword in keywords)

  ...{

    string temp = keyword;

    query = query.Where (p => p.Description.Contains (temp));

  }

  return query;

}

The temporary variable in the loop is required to avoid the outer
variable trap, where the same variable is captured for each iteration of
the foreach loop.

So far, so good. But this only handles the case where you want to match
all of the specified keywords. Suppose
instead, we wanted products whose description contains any of the supplied keywords. Our previous
approach of chaining Where operators is completely useless! We could
instead chain Union operators, but this would be inefficient. The ideal
approach is to dynamically construct a lambda expression tree that
performs an or-based predicate.

Of all the things that will drive you to manually constructing
expression trees, the need for dynamic predicates is the most common in
a typical business application. Fortunately, it’s possible to write a
set of simple and reusable extension methods that radically simplify
this task. This is the role of our PredicateBuilder class.

当下是PredicateBuilder的源文件

Using PredicateBuilder

Here’s how to solve the preceding example with PredicateBuilder:

 

IQueryable<Product> SearchProducts (params string[] keywords)

...{

  var predicate = PredicateBuilder.False<Product>();



  foreach (string keyword in keywords)

  ...{

    string temp = keyword;

    predicate = predicate.Or (p => p.Description.Contains (temp));

  }

  return dataContext.Products.Where (predicate);

}

lovebet体育官网 1 public static class PredicateBuilder
lovebet体育官网 2lovebet体育官网 3    …{
lovebet体育官网 4lovebet体育官网 5      public static Expression<Func<T, bool>> True<T> ()  …{ return f => true;  }
lovebet体育官网 6lovebet体育官网 7      public static Expression<Func<T, bool>> False<T> () …{ return f => false; }
lovebet体育官网 8     
lovebet体育官网 9      public static Expression<Func<T, bool>> Or<T> (this Expression<Func<T, bool>> expr1,
lovebet体育官网 10                                                          Expression<Func<T, bool>> expr2)
lovebet体育官网 11lovebet体育官网 12      …{
lovebet体育官网 13        var invokedExpr = Expression.Invoke (expr2, expr1.Parameters.Cast<Expression> ());
lovebet体育官网 14        return Expression.Lambda<Func<T, bool>>
lovebet体育官网 15              (Expression.Or (expr1.Body, invokedExpr), expr1.Parameters);
lovebet体育官网 16      }
lovebet体育官网 17     
lovebet体育官网 18      public static Expression<Func<T, bool>> And<T> (this Expression<Func<T, bool>> expr1,
lovebet体育官网 19                                                           Expression<Func<T, bool>> expr2)
lovebet体育官网 20lovebet体育官网 21      …{
lovebet体育官网 22        var invokedExpr = Expression.Invoke (expr2, expr1.Parameters.Cast<Expression> ());
lovebet体育官网 23        return Expression.Lambda<Func<T, bool>>
lovebet体育官网 24              (Expression.And (expr1.Body, invokedExpr), expr1.Parameters);
lovebet体育官网 25      }
lovebet体育官网 26    }

PredicateBuilder Source Code

Here’s the complete source:

lovebet体育官网 27using System;
lovebet体育官网 28using System.Linq;
lovebet体育官网 29using System.Linq.Expressions;
lovebet体育官网 30using System.Collections.Generic;
lovebet体育官网 31 
lovebet体育官网 32public static class PredicateBuilder
lovebet体育官网 33lovebet体育官网 34…{
lovebet体育官网 35lovebet体育官网 36  public static Expression<Func<T, bool>> True<T> ()  …{ return f => true;  }
lovebet体育官网 37lovebet体育官网 38  public static Expression<Func<T, bool>> False<T> () …{ return f => false; }
lovebet体育官网 39 
lovebet体育官网 40  public static Expression<Func<T, bool>> Or<T> (this Expression<Func<T, bool>> expr1,
lovebet体育官网 41                                                      Expression<Func<T, bool>> expr2)
lovebet体育官网 42lovebet体育官网 43  …{
lovebet体育官网 44    var invokedExpr = Expression.Invoke (expr2, expr1.Parameters.Cast<Expression> ());
lovebet体育官网 45    return Expression.Lambda<Func<T, bool>>
lovebet体育官网 46          (Expression.Or (expr1.Body, invokedExpr), expr1.Parameters);
lovebet体育官网 47  }
lovebet体育官网 48 
lovebet体育官网 49  public static Expression<Func<T, bool>> And<T> (this Expression<Func<T, bool>> expr1,
lovebet体育官网 50                                                       Expression<Func<T, bool>> expr2)
lovebet体育官网 51lovebet体育官网 52  …{
lovebet体育官网 53    var invokedExpr = Expression.Invoke (expr2, expr1.Parameters.Cast<Expression> ());
lovebet体育官网 54    return Expression.Lambda<Func<T, bool>>
lovebet体育官网 55          (Expression.And (expr1.Body, invokedExpr), expr1.Parameters);
lovebet体育官网 56  }
lovebet体育官网 57}

 

PredicateBuilder is also shipped as part of
LINQKit, a productivity
kit for LINQ to SQL.

 

How it Works

The True and False
methods do nothing special: they are simply convenient shortcuts for
creating an Expression<Func<T,bool>> that initially
evaluates to true or false. So the following:

var predicate = PredicateBuilder.True <Product> ();

is just a shortcut for this:

Expression<Func<Product, bool>> predicate = c => true;

When you’re building a predicate by repeatedly stacking and/or conditions,
it’s useful to have a starting point of either true or false
(respectively). Our SearchProducts method still
works if no keywords are supplied.

The interesting work takes place inside the And
and Or methods. We start by invoking the second expression with the first
expression’s parameters. An Invoke expression
calls another lambda expression using the given expressions as
arguments. We can create the conditional expression from the body of the
first expression and the invoked version
of the second. The final step is to wrap this in a new lambda
expression.

下面是采取示例 :

More Examples

A useful pattern in writing a data access layer is to create a reusable
predicate library. Your queries, then, consist largely of select and orderby clauses,
the filtering logic farmed out to your library. Here’s a simple example:

public partial class Product

...{

  public static Expression<Func<Product, bool>> IsSelling()

  ...{

    return p => !p.Discontinued && p.LastSale > DateTime.Now.AddDays (-30);

  }

}

We can extend this by adding a method that uses PredicateBuilder:

lovebet体育官网 58public partial class Product
lovebet体育官网 59lovebet体育官网 60…{
lovebet体育官网 61  public static Expression<Func<Product, bool>> ContainsInDescription (
lovebet体育官网 62                                                params string[] keywords)
lovebet体育官网 63lovebet体育官网 64  …{
lovebet体育官网 65    var predicate = PredicateBuilder.False<Product>();
lovebet体育官网 66    foreach (string keyword in keywords)
lovebet体育官网 67lovebet体育官网 68    …{
lovebet体育官网 69      string temp = keyword;
lovebet体育官网 70      predicate = predicate.Or (p => p.Description.Contains (temp));
lovebet体育官网 71    }
lovebet体育官网 72    return predicate;
lovebet体育官网 73  }
lovebet体育官网 74}

This offers an excellent balance of simplicity and reusability, as well
as separating business logic from expression plumbing logic. To retrieve
all products whose description contains “BlackBerry” or “iPhone”, along
with the Nokias and Ericssons that are selling, you would do this:

var newKids  = Product.ContainsInDescription ("BlackBerry", "iPhone");



var classics = Product.ContainsInDescription ("Nokia", "Ericsson")

                      .And (Product.IsSelling());

var query =

  from p in Data.Products.Where (newKids.Or (classics))

  select p;

The And and Or methods
in boldface resolve to extension methods in PredicateBuilder.
An expression predicate can perform. the equivalent of an SQL subquery
by referencing association properties. So, if Product had a child EntitySet called Purchases, we could refine our IsSelling method to return only those products that
have sold a minimum number of units as follows:

public static Expression<Func<Product, bool>> IsSelling (int minPurchases)

...{

  return prod =>

    !prod.Discontinued &&

     prod.Purchases.Where (purch => purch.Date > DateTime.Now.AddDays(-30))

                    .Count() >= minPurchases;

}

 

 

lovebet体育官网 75List<Product> GetProductsByAND(params string[] keywords) 
lovebet体育官网 76lovebet体育官网 77    …{
lovebet体育官网 78        DBDataContext db = new DBDataContext(Database.ConnectionString);
lovebet体育官网 79        IQueryable<Product> query = db.Products;
lovebet体育官网 80        foreach (string keyword in keywords)
lovebet体育官网 81lovebet体育官网 82        …{
lovebet体育官网 83            string temp = keyword;
lovebet体育官网 84            query = query.Where(p => p.Description.Contains(temp));
lovebet体育官网 85        }
lovebet体育官网 86        //翻译后底sql语句:
lovebet体育官网 87        //Select [t0].[ID], [t0].[Name], [t0].[Description]
lovebet体育官网 88        //FROM [dbo].[Product] AS [t0]
lovebet体育官网 89        //Where ([t0].[Description] LIKE ‘%手机%’) AND ([t0].[Description] LIKE ‘%6111%’)
lovebet体育官网 90        return query.ToList();   
lovebet体育官网 91    }
lovebet体育官网 92
lovebet体育官网 93
lovebet体育官网 94    List<Product> GetProductsByOR(params string[] keywords)
lovebet体育官网 95lovebet体育官网 96    …{
lovebet体育官网 97        DBDataContext db = new DBDataContext(Database.ConnectionString);
lovebet体育官网 98        var predicate = PredicateBuilder.False<Product>();
lovebet体育官网 99        foreach (string keyword in keywords)
lovebet体育官网 100lovebet体育官网 101        …{
lovebet体育官网 102            string temp = keyword;
lovebet体育官网 103            predicate = predicate.Or(p => p.Description.Contains(temp));
lovebet体育官网 104        }
lovebet体育官网 105        var query = db.Products.Where(predicate);
lovebet体育官网 106        //翻译后底sql语句:
lovebet体育官网 107        //Select [t0].[ID], [t0].[Name], [t0].[Description]
lovebet体育官网 108        //FROM [dbo].[Product] AS [t0]
lovebet体育官网 109        //Where ([t0].[Description] LIKE ‘%6111%’) OR ([t0].[Description] LIKE ‘%2350%’)
lovebet体育官网 110        return query.ToList();
lovebet体育官网 111    }
lovebet体育官网 112
lovebet体育官网 113    void ShowData() 
lovebet体育官网 114lovebet体育官网 115    …{
lovebet体育官网 116        //var _products = GetProductsByOR(“6111”, “2350”);
lovebet体育官网 117        //Repeater1.DataSource = _products;
lovebet体育官网 118        //Repeater1.DataBind();
lovebet体育官网 119
lovebet体育官网 120        var predicate = PredicateBuilder.True<Product>();
lovebet体育官网 121
lovebet体育官网 122        string _name = “6111”;
lovebet体育官网 123        if (!string.IsNullOrEmpty(_name)) 
lovebet体育官网 124lovebet体育官网 125        …{
lovebet体育官网 126            predicate = predicate.And(p => p.Name.Contains(_name));
lovebet体育官网 127        }
lovebet体育官网 128
lovebet体育官网 129        string _description = “长虹”;
lovebet体育官网 130        if (!string.IsNullOrEmpty(_description)) 
lovebet体育官网 131lovebet体育官网 132        …{
lovebet体育官网 133            predicate = predicate.And(p => p.Description.Contains(_description));
lovebet体育官网 134        }
lovebet体育官网 135
lovebet体育官网 136        using (DBDataContext db = new DBDataContext(Database.ConnectionString))
lovebet体育官网 137lovebet体育官网 138        …{
lovebet体育官网 139            var _Products = db.Products.Where(predicate);
lovebet体育官网 140            Repeater1.DataSource = _Products;
lovebet体育官网 141            Repeater1.DataBind();
lovebet体育官网 142        }
lovebet体育官网 143
lovebet体育官网 144    }

 

相关文章