您的位置:首页 > 编程语言 > C#

c#——表达式树在LINQ动态查询

2015-10-30 11:22 639 查看
一般如果逻辑比较简单,只是存在有的情况多一个查询条件,有的情况不需要添加该查询条件

简单方式这样操作就可以了

public IQueryable<FileImport> DynamicChainedSyntax
(IQueryable<FileImport> files, bool pastOnly)
{
var query = files.Where(file => file.ImportDate >
DateTime.Now.AddDays(-7));
if (pastOnly)
query = query.Where(file => file.ImportDate <
DateTime.Today);
return query;
}


这里的多个where条件是AND关系,如果是OR的关系,可将多次查询的结果进行union

当然大多数的时候,我们是希望能够动态构建查询条件的,你可以针对任何字段进行任何操作符形式的查询,不同查询条件之间的关系也是可以动态定义的。

这时候表达式树就派上用场了,关于表达式树的基础知识已经在上一篇中提到了。

这里主要说如何构建linq中Where查询条件,其实只是熟悉表达式树的其他提供的方法,非常简单。

public Func<TSource, bool> SimpleComparison<TSource>
string property, object value)
{
var type = typeof (TSource);
var pe = Expression.Parameter(type, "p");
var propertyReference = Expression.Property(pe, property);
var constantReference = Expression.Constant(value);
return Expression.Lambda<Func<TSource, bool>>
(Expression.Equal(propertyReference, constantReference),
new[] { pe }).Compile();
}


呵呵,话到这里,看看我的小DEMO

using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using System.Threading.Tasks;

namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
//(a,b)=>(a+b)
//参数的构建  (定义参数的名字和参数的类型)
ParameterExpression exp1 = Expression.Parameter(typeof(int), "a");
ParameterExpression exp2 = Expression.Parameter(typeof(int), "b");
//表达式主体的构建
BinaryExpression exp = Expression.Add(exp1, exp2);
//表达式树的构建(如下定义,表达式的类型为Lambda
//lambda表达式的类型为Func<int, int, int>)
var lambda = Expression.Lambda<Func<int, int, int>>(exp, exp1, exp2);

//p=>p.Name 可以动态构建OrderBy
ParameterExpression exp3 = Expression.Parameter(typeof(Person), "p");
var property = Expression.Property(exp3, "Name");
var lambda2 = Expression.Lambda<Func<Person, string>>(property, exp3);

//p=>p.Name == "daisy"
List<Person> persons = new List<Person>()
{ new Person(){ Name = "daisy", age = 10 },
new Person(){ Name = "daisy", age = 12 },
new Person(){Name="dom", age=12},
new Person(){Name="caren", age=10}};
var compareExp = simpleCompare<Person>("Name", "daisy");
var daisys = persons.Where(compareExp).ToList();
foreach (var item in daisys)
{
Console.WriteLine("Name:  "+item.Name+"    Age:  "+item.age);
}
Console.ReadKey();
}
public static Func<TSource, bool> simpleCompare<TSource>(string property, object value)
{
var type = typeof(TSource);
var pe = Expression.Parameter(type, "p");
var propertyReference = Expression.Property(pe, property);
var constantReference = Expression.Constant(value);

//compile 是表达式的一个接口,生成该lambda表达式树对的委托
return Expression.Lambda<Func<TSource, bool>>(Expression.Equal(propertyReference, constantReference), pe).Compile();
}

}
public class Person
{
public string Name { get; set; }
public int age { get; set; }
}
}


再来看看查询结果:



嗯,理解起来还是非常简单的,就是构建表达式树,返回我们需要的委托类型!

接下来猛料哦

动态构建表达式树,最佳实践版,很实用!

public class FilterCollection : Collection<IList<Filter>>
{
public FilterCollection()
: base()
{ }
}

public class Filter
{
public string PropertyName { get; set; }
public Op Operation { get; set; }
public object Value { get; set; }
}

public enum Op
{
Equals,
GreaterThan,
LessThan,
GreaterThanOrEqual,
LessThanOrEqual,
Contains,
StartsWith,
EndsWith
}


通过上面的类可以动态构建复杂的查询条件,下面具体调用的类哦

using Infrastructure.Model;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;

namespace Infrastructure.Operation
{
public static class LambdaExpressionBuilder
{
private static MethodInfo containsMethod = typeof(string).GetMethod("Contains");
private static MethodInfo startsWithMethod =
typeof(string).GetMethod("StartsWith", new Type[] { typeof(string) });
private static MethodInfo endsWithMethod =
typeof(string).GetMethod("EndsWith", new Type[] { typeof(string) });
private static Expression GetExpression(ParameterExpression param, Filter filter)
{
MemberExpression member = Expression.Property(param, filter.PropertyName);
Expression handledMember = member;
ConstantExpression constant = Expression.Constant(filter.Value);

if (member.Member.MemberType == MemberTypes.Property)
{
Type propertyType = ((PropertyInfo)member.Member).PropertyType;
if (propertyType == typeof(string))
{
handledMember = Expression.Call(member, typeof(string).GetMethod("ToLower", System.Type.EmptyTypes));
}
if (propertyType == typeof(DateTime?))
{
handledMember = Expression.Property(member, typeof(DateTime?).GetProperty("Value"));
}
}

switch (filter.Operation)
{
case Op.Equals:
return Expression.Equal(handledMember, constant);
case Op.GreaterThan:
return Expression.GreaterThan(handledMember, constant);
case Op.GreaterThanOrEqual:
return Expression.GreaterThanOrEqual(handledMember, constant);
case Op.LessThan:
return Expression.LessThan(handledMember, constant);
case Op.LessThanOrEqual:
return Expression.LessThanOrEqual(handledMember, constant);
case Op.Contains:
return Expression.Call(handledMember, containsMethod, constant);
case Op.StartsWith:
return Expression.Call(handledMember, startsWithMethod, constant);
case Op.EndsWith:
return Expression.Call(handledMember, endsWithMethod, constant);
}

return null;
}
private static BinaryExpression GetORExpression(ParameterExpression param, Filter filter1, Filter filter2)
{
Expression bin1 = GetExpression(param, filter1);
Expression bin2 = GetExpression(param, filter2);

return Expression.Or(bin1, bin2);
}

private static Expression GetExpression(ParameterExpression param, IList<Filter> orFilters)
{
if (orFilters.Count == 0)
return null;

Expression exp = null;

if (orFilters.Count == 1)
{
exp = GetExpression(param, orFilters[0]);
}
else if (orFilters.Count == 2)
{
exp = GetORExpression(param, orFilters[0], orFilters[1]);
}
else
{
while (orFilters.Count > 0)
{
var f1 = orFilters[0];
var f2 = orFilters[1];

if (exp == null)
{
exp = GetORExpression(param, orFilters[0], orFilters[1]);
}
else
{
exp = Expression.Or(exp, GetORExpression(param, orFilters[0], orFilters[1]));
}
orFilters.Remove(f1);
orFilters.Remove(f2);

if (orFilters.Count == 1)
{
exp = Expression.Or(exp, GetExpression(param, orFilters[0]));
orFilters.RemoveAt(0);
}
}
}

return exp;
}

public static Expression<Func<T, bool>> GetExpression<T>(FilterCollection filters)
{
if (filters == null || filters.Count == 0)
return null;

ParameterExpression param = Expression.Parameter(typeof(T), "t");
Expression exp = null;

if (filters.Count == 1)
{
exp = GetExpression(param, filters[0]);
}
else if (filters.Count == 2)
{
exp = Expression.AndAlso(GetExpression(param, filters[0]), GetExpression(param, filters[1]));
}

else
{
while (filters.Count > 0)
{
var f1 = filters[0];
var f2 = filters[1];
var f1Andf2 = Expression.AndAlso(GetExpression(param, filters[0]), GetExpression(param, filters[1]));
if (exp == null)
{
exp = f1Andf2;
}
else
{
exp = Expression.AndAlso(exp, f1Andf2);
}

filters.Remove(f1);
filters.Remove(f2);

if (filters.Count == 1)
{
exp = Expression.AndAlso(exp, GetExpression(param, filters[0]));
filters.RemoveAt(0);
}
}
}

return Expression.Lambda<Func<T, bool>>(exp, param);
}
}
}


再来一个OrderBy动态构建

using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Text;

namespace Jurassic.Sooil.Com
{
public static class OrderExpression
{
public static IOrderedQueryable<T> OrderBy<T>(this IQueryable<T> source, string property)
{
return ApplyOrder<T>(source, property, "OrderBy");
}
public static IOrderedQueryable<T> OrderByDescending<T>(this IQueryable<T> source, string property)
{
return ApplyOrder<T>(source, property, "OrderByDescending");
}
public static IOrderedQueryable<T> ThenBy<T>(this IOrderedQueryable<T> source, string property)
{
return ApplyOrder<T>(source, property, "ThenBy");
}
public static IOrderedQueryable<T> ThenByDescending<T>(this IOrderedQueryable<T> source, string property)
{
return ApplyOrder<T>(source, property, "ThenByDescending");
}
static IOrderedQueryable<T> ApplyOrder<T>(IQueryable<T> source, string property, string methodName)
{
string[] props = property.Split('.');
Type type = typeof(T);
ParameterExpression arg = Expression.Parameter(type, "x");
Expression expr = arg;
foreach (string prop in props)
{
// use reflection (not ComponentModel) to mirror LINQ
PropertyInfo pi = type.GetProperty(prop);
expr = Expression.Property(expr, pi);
type = pi.PropertyType;
}
Type delegateType = typeof(Func<,>).MakeGenericType(typeof(T), type);
LambdaExpression lambda = Expression.Lambda(delegateType, expr, arg);

object result = typeof(Queryable).GetMethods().Single(
method => method.Name == methodName
&& method.IsGenericMethodDefinition
&& method.GetGenericArguments().Length == 2
&& method.GetParameters().Length == 2)
.MakeGenericMethod(typeof(T), type)
.Invoke(null, new object[] { source, lambda });
return (IOrderedQueryable<T>)result;
}
}
}


至此动态构建LINQ查询结束!花了上班时间一上午,还是相当值得的,不过被项目经理知道了得哭死!

不管如何,学到手的才是自己的!
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: