You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

293 lines
12 KiB

using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
namespace Zxw.Framework.NetCore.Extensions
{
/// <summary>
/// 表达式树常用扩展方法
/// </summary>
public static class ExpressionExtensions
{
/// <summary>
/// 取的 Expression<Func
/// <T, TProperty>
/// > predicate 表达式对应的属性名称
/// 例如:c=>c.Value.Year 侧返回:Value.Year
/// </summary>
/// <typeparam name="T"></typeparam>
/// <typeparam name="TProperty"></typeparam>
/// <param name="predicate"></param>
/// <returns></returns>
public static string GetPropertyName<T, TProperty>(this Expression<Func<T, TProperty>> predicate)
{
MemberExpression expression = predicate.Body as MemberExpression;
//return expression.Member.Name; //该属性只返回最后一个属性,因此采用下面方法返回。
return expression.ToString().Substring(2);
}
public static ParameterExpression CreateLambdaParam<T>(string name)
{
return Expression.Parameter(typeof(T), name);
}
/// <summary>
/// 创建linq表达示的body部分
/// </summary>
public static Expression GenerateBody<T>(this ParameterExpression param, Filter filterObj)
{
System.Reflection.PropertyInfo property = typeof(T).GetProperty(filterObj.Key);
//组装左边
Expression left = Expression.Property(param, property);
//组装右边
Expression right = null;
if (property.PropertyType == typeof(int))
{
right = Expression.Constant(int.Parse(filterObj.Value));
}
else if (property.PropertyType == typeof(DateTime))
{
right = Expression.Constant(DateTime.Parse(filterObj.Value));
}
else if (property.PropertyType == typeof(string))
{
right = Expression.Constant(filterObj.Value);
}
else if (property.PropertyType == typeof(decimal))
{
right = Expression.Constant(decimal.Parse(filterObj.Value));
}
else if (property.PropertyType == typeof(Guid))
{
right = Expression.Constant(Guid.Parse(filterObj.Value));
}
else if (property.PropertyType == typeof(bool))
{
right = Expression.Constant(filterObj.Value.Equals("1"));
}
else if (property.PropertyType == typeof(Guid?))
{
left = Expression.Property(left, "Value");
right = Expression.Constant(Guid.Parse(filterObj.Value));
}
else
{
throw new Exception("暂不能解析该Key的类型");
}
//c.XXX=="XXX"
Expression filter = Expression.Equal(left, right);
switch (filterObj.Contrast)
{
case "<=":
filter = Expression.LessThanOrEqual(left, right);
break;
case "<":
filter = Expression.LessThan(left, right);
break;
case ">":
filter = Expression.GreaterThan(left, right);
break;
case ">=":
filter = Expression.GreaterThanOrEqual(left, right);
break;
case "!=":
filter = Expression.NotEqual(left, right);
break;
case "like":
filter = Expression.Call(left, typeof(string).GetMethod("Contains", new[] { typeof(string) }),
Expression.Constant(filterObj.Value));
break;
case "not in":
ConstantExpression listExpression = Expression.Constant(filterObj.Value.Split(',').ToList()); //数组
System.Reflection.MethodInfo method = typeof(List<int>).GetMethod("Contains", new[] { typeof(string) }); //Contains语句
filter = Expression.Not(Expression.Call(listExpression, method, left));
break;
case "in":
ConstantExpression lExp = Expression.Constant(filterObj.Value.Split(',').ToList()); //数组
System.Reflection.MethodInfo methodInfo =
typeof(List<int>).GetMethod("Contains", new[] { typeof(string) }); //Contains语句
filter = Expression.Call(lExp, methodInfo, left);
break;
}
return filter;
}
public static Expression<Func<T, bool>> GenerateTypeBody<T>(this ParameterExpression param, Filter filterObj)
{
return (Expression<Func<T, bool>>)param.GenerateBody<T>(filterObj);
}
/// <summary>
/// 创建完整的lambda
/// </summary>
public static LambdaExpression GenerateLambda(this ParameterExpression param, Expression body)
{
//c=>c.XXX=="XXX"
return Expression.Lambda(body, param);
}
public static Expression<Func<T, bool>> GenerateTypeLambda<T>(this ParameterExpression param, Expression body)
{
return (Expression<Func<T, bool>>)param.GenerateLambda(body);
}
public static Expression AndAlso(this Expression expression, Expression expressionRight)
{
return Expression.AndAlso(expression, expressionRight);
}
public static Expression Or(this Expression expression, Expression expressionRight)
{
return Expression.Or(expression, expressionRight);
}
public static Expression And(this Expression expression, Expression expressionRight)
{
return Expression.And(expression, expressionRight);
}
//系统已经有该函数的实现
//public static IQueryable<T> Where<T>(this IQueryable<T> query, Expression expression)
//{
// Expression expr = Expression.Call(typeof(Queryable), "Where", new[] { typeof(T) },
// Expression.Constant(query), expression);
// //生成动态查询
// IQueryable<T> result = query.Provider.CreateQuery<T>(expr);
// return result;
//}
public static IQueryable<T> GenerateFilter<T>(this IQueryable<T> query, string filterjson)
{
if (!string.IsNullOrEmpty(filterjson))
{
IEnumerable<Filter> filters = JsonConvert.DeserializeObject<IEnumerable<Filter>>(filterjson);
ParameterExpression param = CreateLambdaParam<T>("c");
Expression result = Expression.Constant(true);
foreach (Filter filter in filters)
{
result = result.AndAlso(param.GenerateBody<T>(filter));
}
query = query.Where(param.GenerateTypeLambda<T>(result));
}
return query;
}
/// <summary>
/// 以特定的条件运行组合两个Expression表达式
/// </summary>
/// <typeparam name="T">表达式的主实体类型</typeparam>
/// <param name="first">第一个Expression表达式</param>
/// <param name="second">要组合的Expression表达式</param>
/// <param name="merge">组合条件运算方式</param>
/// <returns>组合后的表达式</returns>
public static Expression<T> Compose<T>(this Expression<T> first, Expression<T> second,
Func<Expression, Expression, Expression> merge)
{
// build parameter map (from parameters of second to parameters of first)
Dictionary<ParameterExpression, ParameterExpression> map =
first.Parameters.Select((f, i) => new { f, s = second.Parameters[i] }).ToDictionary(p => p.s, p => p.f);
// replace parameters in the second lambda expression with parameters from the first
Expression secondBody = ParameterRebinder.ReplaceParameters(map, second.Body);
// apply composition of lambda expression bodies to parameters from the first expression
return Expression.Lambda<T>(merge(first.Body, secondBody), first.Parameters);
}
/// <summary>
/// 以 Expression.AndAlso 组合两个Expression表达式
/// </summary>
/// <typeparam name="T">表达式的主实体类型</typeparam>
/// <param name="first">第一个Expression表达式</param>
/// <param name="second">要组合的Expression表达式</param>
/// <returns>组合后的表达式</returns>
public static Expression<Func<T, bool>> And<T>(this Expression<Func<T, bool>> first,
Expression<Func<T, bool>> second)
{
return first.Compose(second, Expression.AndAlso);
}
/// <summary>
/// 以 Expression.OrElse 组合两个Expression表达式
/// </summary>
/// <typeparam name="T">表达式的主实体类型</typeparam>
/// <param name="first">第一个Expression表达式</param>
/// <param name="second">要组合的Expression表达式</param>
/// <returns>组合后的表达式</returns>
public static Expression<Func<T, bool>> Or<T>(this Expression<Func<T, bool>> first,
Expression<Func<T, bool>> second)
{
return first.Compose(second, Expression.OrElse);
}
/// <summary>
/// 参数重新绑定
/// </summary>
/// <seealso cref="System.Linq.Expressions.ExpressionVisitor" />
private class ParameterRebinder : ExpressionVisitor
{
private readonly Dictionary<ParameterExpression, ParameterExpression> _map;
/// <summary>
/// Initializes a new instance of the <see cref="ParameterRebinder" /> class.
/// </summary>
/// <param name="map">The map.</param>
private ParameterRebinder(Dictionary<ParameterExpression, ParameterExpression> map)
{
_map = map ?? new Dictionary<ParameterExpression, ParameterExpression>();
}
/// <summary>
/// Replaces the parameters.
/// </summary>
/// <param name="map">The map.</param>
/// <param name="exp">The exp.</param>
/// <returns></returns>
public static Expression ReplaceParameters(Dictionary<ParameterExpression, ParameterExpression> map,
Expression exp)
{
return new ParameterRebinder(map).Visit(exp);
}
/// <summary>
/// 访问 <see cref="T:System.Linq.Expressions.ParameterExpression" />。
/// </summary>
/// <param name="node">要访问的表达式。</param>
/// <returns>
/// 如果修改了该表达式或任何子表达式,则为修改后的表达式;否则返回原始表达式。
/// </returns>
protected override Expression VisitParameter(ParameterExpression node)
{
if (_map.TryGetValue(node, out ParameterExpression replacement))
{
node = replacement;
}
return base.VisitParameter(node);
}
}
}
public class Filter
{
public string Key { get; set; }
public string Value { get; set; }
public string Contrast { get; set; }
}
}