重视Linq技术_5
Building Query Expressions
//1、Compiling Expression Trees
Products.DeleteAllOnSubmit (Products.Where (p => p.ID == 999)); Products.InsertOnSubmit (new Product { ID = 999, Description = "Test", LastSale = DateTime.Now } ); SubmitChanges(); Product[] localProducts = Products.ToArray(); Expression<Func<Product, bool>> isSelling = p => !p.Discontinued && p.LastSale > DateTime.Now.AddDays (-30); IQueryable<Product> sqlQuery = Products.Where (isSelling); IEnumerable<Product> localQuery = localProducts.Where (isSelling.Compile()); sqlQuery.Dump ("SQL Query"); localQuery.Dump ("Local Query, using same predicate"); //Compiling Expression Trees
Products.DeleteAllOnSubmit (Products.Where (p => p.ID == 999)); Products.InsertOnSubmit (new Product { ID = 999, Description = "Test", LastSale = DateTime.Now } ); SubmitChanges(); Product[] localProducts = Products.ToArray(); Expression<Func<Product, bool>> isSelling = p => !p.Discontinued && p.LastSale > DateTime.Now.AddDays (-30); IQueryable<Product> sqlQuery = Products.Where (isSelling); IEnumerable<Product> localQuery = localProducts.Where (isSelling.Compile()); sqlQuery.Dump ("SQL Query"); localQuery.Dump ("Local Query, using same predicate");//2、AsQueryable
{
FilterSortProducts (Products).Dump ("This query executes on SQL Server");
Product[] localProducts =
{
new Product { ID = 1, Description = "Local Product Test", LastSale = new DateTime (2007, 2, 3) }
};
FilterSortProducts (localProducts.AsQueryable()).Dump ("The same query - executing locally");
}
IQueryable<Product> FilterSortProducts (IQueryable<Product> input)
{
return
from p in input
where !p.Discontinued && p.LastSale < DateTime.Now.AddDays (-7)
orderby p.Description
select p;
}
f.Body.NodeType.Dump ("Body.NodeType");
(((BinaryExpression) f.Body).Right).Dump ("Body.Right");
f.Dump ("The whole expression tree");
//4、Building an Expression Tree ?
MemberExpression stringLength = Expression.Property (p, "Length");
ConstantExpression five = Expression.Constant (5);
BinaryExpression comparison = Expression.LessThan (stringLength, five);
Expression<Func<string, bool>> lambda = Expression.Lambda<Func<string, bool>> (comparison, p);
Func<string, bool> runnable = lambda.Compile();
runnable ("kangaroo") .Dump ("kangaroo is less than 5 characters");
runnable ("dog") .Dump ("dog is less than 5 characters");
//kangaroo is less than 5 characters
//False
//dog is less than 5 characters
//True
var predicate = PredicateBuilder.False<Product>();
foreach (string keyword in keywords)
{
string temp = keyword;
predicate = predicate.Or (p => p.Description.Contains (temp));
}
Products.Where(predicate).Dump("Notice the multiple OR clauses in the SQL pane");
//6、Extra - Dynamic Ordering Sample
IQueryable query = // The original unordered query
from p in Purchases
where p.Price > 100
select p;
string propToOrderBy = "Price"; // Try changing this to "Description" or "Date"
ParameterExpression purchaseParam = Expression.Parameter (typeof (Purchase), "p");
MemberExpression member = Expression.PropertyOrField (purchaseParam, propToOrderBy);
LambdaExpression lambda = Expression.Lambda (member, purchaseParam);
Type[] exprArgTypes = { query.ElementType, lambda.Body.Type };
MethodCallExpression methodCall =
Expression.Call (typeof (Queryable), "OrderBy", exprArgTypes, query.Expression, lambda);
IQueryable orderedQuery = query.Provider.CreateQuery (methodCall);
orderedQuery.Dump();
//7、Extra - Dynamic Ordering Sample - How it Words
// that the query does not evaluate at this point, thanks to deferred execution):
IQueryable<Purchase> query = // The original unordered query
from p in Purchases
where p.Price > 100
select p;
// Here's the property or field name upon which we want to order:
string propToOrderBy = "Price"; // Try changing this to "Description" or "Date"
// The aim is to dynamically constuct the following:
// var orderedQuery = query.OrderBy (p => p.Price);
// Starting from the inside out, we start by creating the lambda expression, p => p.Price.
// To dynamically build a LambaExpression, we first create the parameter, in this case, p.
// Our parameter is of type Purchase, and is called "p":
ParameterExpression purchaseParam = Expression.Parameter (typeof (Purchase), "p");
purchaseParam.Dump ("purchaseParam");
// Next, we need to create "p.Price". The static method Expression.PropertyOrField returns
// a MemberExpression that finds a property or field with the given name:
MemberExpression member = Expression.PropertyOrField (purchaseParam, propToOrderBy);
member.Dump ("member");
// With these two things, we build the LambdaExpression:
LambdaExpression lambda = Expression.Lambda (member, purchaseParam);
lambda.Dump ("lambda");
lambda.ToString().Dump ("lambda.ToString");
// We now need to wrap the lambda expression in a MethodCallExpression that
// references the Queryable.OrderBy method. For this, we call the static Expresion.Call
// method, which is overloaded especially to simplify the task of invoking methods
// that accept lambda expressions:
Type[] exprArgTypes = { query.ElementType, lambda.Body.Type };
MethodCallExpression methodCall =
Expression.Call (
typeof (Queryable), // Type defining method we want to call
"OrderBy", // Name of method to call
exprArgTypes, // Generic argument types
query.Expression, // First argument (the query expression body)
lambda); // Second argument (the lambda expression)
methodCall.Dump ("methodCall (notice all the work that Expression.Call does for us)");
// The final step is to create the new query, which calls the expression we've just
//created. For this, we use the Provider property exposed by the IQueryable interface,
// which returns an object upon which we call CreateQuery:
IQueryable orderedQuery = query.Provider.CreateQuery (methodCall);
// (Exactly the same thing happens when you ordinarily call Queryable.OrderBy;
// a good way to see this is to download Lutz Roeder's Reflector at
// http://www.aisto.com/roeder/dotnet/ and look at Queryable's OrderBy method).
// Here's the final result:
orderedQuery.Expression.ToString().Dump ("The final result");