using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
namespace YBEE.EQM.Core
{
///
/// 动态生成查询表达式
///
public static class LambdaExpressionBuilder
{
private static Expression GetExpression(ParameterExpression parameter, Condition condition)
{
var propertyParam = Expression.Property(parameter, condition.Field);
var propertyInfo = propertyParam.Member as PropertyInfo;
if (propertyInfo == null)
throw new MissingMemberException(nameof(Condition), condition.Field);
//Support Nullable<>
var realPropertyType = Nullable.GetUnderlyingType(propertyInfo.PropertyType) ?? propertyInfo.PropertyType;
if (propertyInfo.PropertyType.IsGenericType &&
propertyInfo.PropertyType.GetGenericTypeDefinition() == typeof(Nullable<>))
propertyParam = Expression.Property(propertyParam, "Value");
//Support IEnumerable && IEnumerable
if (condition.Op != QueryTypeEnum.StdIn && condition.Op != QueryTypeEnum.StdNotIn)
{
condition.Value = Convert.ChangeType(condition.Value, realPropertyType);
}
else
{
var typeOfValue = condition.Value.GetType();
var typeOfList = typeof(IEnumerable<>).MakeGenericType(realPropertyType);
if (typeOfValue.IsGenericType && typeOfList.IsAssignableFrom(typeOfValue))
condition.Value = typeof(Enumerable)
.GetMethod("ToArray", BindingFlags.Public | BindingFlags.Static)
?.MakeGenericMethod(realPropertyType)
.Invoke(null, new[] { condition.Value });
}
var constantParam = Expression.Constant(condition.Value);
switch (condition.Op)
{
case QueryTypeEnum.Equals:
return Expression.Equal(propertyParam, constantParam);
case QueryTypeEnum.NotEquals:
return Expression.NotEqual(propertyParam, constantParam);
case QueryTypeEnum.Contains:
return Expression.Call(propertyParam, "Contains", null, constantParam);
case QueryTypeEnum.NotContains:
return Expression.Not(Expression.Call(propertyParam, "Contains", null, constantParam));
case QueryTypeEnum.StartsWith:
return Expression.Call(propertyParam, "StartsWith", null, constantParam);
case QueryTypeEnum.EndsWith:
return Expression.Call(propertyParam, "EndsWith", null, constantParam);
case QueryTypeEnum.GreaterThan:
return Expression.GreaterThan(propertyParam, constantParam);
case QueryTypeEnum.GreaterThanOrEquals:
return Expression.GreaterThanOrEqual(propertyParam, constantParam);
case QueryTypeEnum.LessThan:
return Expression.LessThan(propertyParam, constantParam);
case QueryTypeEnum.LessThanOrEquals:
return Expression.LessThanOrEqual(propertyParam, constantParam);
case QueryTypeEnum.StdIn:
return Expression.Call(typeof(Enumerable), "Contains", new[] { realPropertyType }, constantParam, propertyParam);
case QueryTypeEnum.StdNotIn:
return Expression.Not(Expression.Call(typeof(Enumerable), "Contains", new[] { realPropertyType }, constantParam, propertyParam));
default:
break;
}
return null;
}
private static Expression GetGroupExpression(ParameterExpression parameter, List orConditions)
{
if (orConditions.Count == 0)
return null;
var exps = orConditions.Select(c => GetExpression(parameter, c)).ToList();
return exps.Aggregate(null, (left, right) =>
left == null ? right : Expression.OrElse(left, right));
}
public static Expression> BuildLambda(IEnumerable conditions)
{
if (conditions == null || !conditions.Any())
return x => true;
var parameter = Expression.Parameter(typeof(T), "x");
//简单条件
var simpleExps = conditions
.ToList()
.FindAll(c => string.IsNullOrEmpty(c.OrGroup))
.Select(c => GetExpression(parameter, c))
.ToList();
//复杂条件
var complexExps = conditions
.ToList()
.FindAll(c => !string.IsNullOrEmpty(c.OrGroup))
.GroupBy(x => x.OrGroup)
.Select(g => GetGroupExpression(parameter, g.ToList()))
.ToList();
var exp = simpleExps.Concat(complexExps).Aggregate(null, (left, right) =>
left == null ? right : Expression.AndAlso(left, right));
return Expression.Lambda>(exp, parameter);
}
public static Expression> BuildAndAlsoLambda(IEnumerable conditions)
{
if (conditions == null || !conditions.Any())
return x => true;
var parameter = Expression.Parameter(typeof(T), "x");
var simpleExps = conditions
.ToList()
.Select(c => GetExpression(parameter, c))
.ToList();
var exp = simpleExps.Aggregate(null, (left, right) =>
left == null ? right : Expression.AndAlso(left, right));
return Expression.Lambda>(exp, parameter);
}
public static Expression> BuildOrElseLambda(IEnumerable conditions)
{
if (conditions == null || !conditions.Any())
return x => true;
var parameter = Expression.Parameter(typeof(T), "x");
var simpleExps = conditions
.ToList()
.Select(c => GetExpression(parameter, c))
.ToList();
var exp = simpleExps.Aggregate(null, (left, right) =>
left == null ? right : Expression.OrElse(left, right));
return Expression.Lambda>(exp, parameter);
}
}
///
/// 查询条件
///
[Serializable]
public class Condition
{
///
/// 字段名
///
public string Field { get; set; }
///
/// 操作符
///
public QueryTypeEnum Op { get; set; }
///
/// 字段值
///
public object Value { get; set; }
///
/// 分组名称
///
public string OrGroup { get; set; }
}
}