9 changed files with 583 additions and 2 deletions
@ -0,0 +1,13 @@ |
|||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
using System.Linq; |
||||
|
using System.Text; |
||||
|
using System.Threading.Tasks; |
||||
|
|
||||
|
namespace Wood.Util.Filters |
||||
|
{ |
||||
|
public class Condition |
||||
|
{ |
||||
|
public ICollection<Filter> Filters { get; set; } = new List<Filter>(); |
||||
|
} |
||||
|
} |
@ -0,0 +1,69 @@ |
|||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
using System.ComponentModel; |
||||
|
using System.Linq; |
||||
|
using System.Text; |
||||
|
using System.Threading.Tasks; |
||||
|
|
||||
|
namespace Wood.Util.Filters |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// 过滤条件
|
||||
|
/// </summary>
|
||||
|
public enum EnumFilterAction |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// equal
|
||||
|
/// </summary>
|
||||
|
[Description("等于")] Equal = 0, |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Not equal
|
||||
|
/// </summary>
|
||||
|
[Description("不等于")] NotEqual = 1, |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Bigger
|
||||
|
/// </summary>
|
||||
|
[Description("大于")] BiggerThan = 2, |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Smaller
|
||||
|
/// </summary>
|
||||
|
[Description("小于")] SmallThan = 3, |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Bigger or equal
|
||||
|
/// </summary>
|
||||
|
[Description("大于等于")] BiggerThanOrEqual = 4, |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Small or equal
|
||||
|
/// </summary>
|
||||
|
[Description("小于等于")] SmallThanOrEqual = 5, |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Like
|
||||
|
/// </summary>
|
||||
|
[Description("类似于")] Like = 6, |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Not like
|
||||
|
/// </summary>
|
||||
|
[Description("不类似于")] NotLike = 7, |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Contained in
|
||||
|
/// List<string > items = new List<string>();
|
||||
|
/// string value = JsonSerializer.Serialize(items);//转成Json字符串
|
||||
|
///FilterCondition filterCondition = new FilterCondition() { Column = "Name", Value = value, Action = EnumFilterAction.In, Logic = EnumFilterLogic.And };
|
||||
|
/// </summary>
|
||||
|
[Description("包含于")] In = 8, |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Not contained in
|
||||
|
/// </summary>
|
||||
|
[Description("不包含于")] NotIn = 9, |
||||
|
} |
||||
|
|
||||
|
} |
@ -0,0 +1,21 @@ |
|||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
using System.Linq; |
||||
|
using System.Text; |
||||
|
using System.Threading.Tasks; |
||||
|
|
||||
|
namespace Wood.Util.Filters |
||||
|
{ |
||||
|
public enum EnumFilterLogic |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// 与
|
||||
|
/// </summary>
|
||||
|
And = 0, |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// 或
|
||||
|
/// </summary>
|
||||
|
Or = 1 |
||||
|
} |
||||
|
} |
@ -0,0 +1,48 @@ |
|||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
using System.Linq; |
||||
|
using System.Text; |
||||
|
using System.Threading.Tasks; |
||||
|
|
||||
|
namespace Wood.Util.Filters |
||||
|
{ |
||||
|
public class Filter |
||||
|
{ |
||||
|
public Filter() |
||||
|
{ |
||||
|
Logic = "And"; |
||||
|
} |
||||
|
|
||||
|
public Filter(string column, string value, |
||||
|
string action = "==", |
||||
|
string logic = "And") |
||||
|
{ |
||||
|
Column = column; |
||||
|
Action = action; |
||||
|
Value = value; |
||||
|
Logic = logic; |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// 过滤条件之间的逻辑关系:AND和OR
|
||||
|
/// </summary>
|
||||
|
public string Logic { get; set; } = "And"; |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// 过滤条件中使用的数据列
|
||||
|
/// </summary>
|
||||
|
public string Column { get; set; } |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// 过滤条件中的操作:==,!=,>,<,>=,<=,In,NotIn,Like,NotLike
|
||||
|
/// Equal、NotEqual、BiggerThan、SmallThan、BiggerThanOrEqual、SmallThanOrEqual、In、NotIn
|
||||
|
/// </summary>
|
||||
|
public string Action { get; set; } = "=="; |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// 过滤条件中的操作的值
|
||||
|
/// </summary>
|
||||
|
public string Value { get; set; } |
||||
|
} |
||||
|
|
||||
|
} |
@ -0,0 +1,337 @@ |
|||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
using System.Globalization; |
||||
|
using System.Linq; |
||||
|
using System.Linq.Expressions; |
||||
|
using System.Text; |
||||
|
using System.Text.Json; |
||||
|
using System.Threading.Tasks; |
||||
|
|
||||
|
namespace Wood.Util.Filters |
||||
|
{ |
||||
|
public static class FilterExtensions |
||||
|
{ |
||||
|
public static Expression<Func<T, bool>> ToLambda<T>(this string jsonFilter) |
||||
|
{ |
||||
|
if (string.IsNullOrWhiteSpace(jsonFilter)) |
||||
|
{ |
||||
|
return p => true; |
||||
|
} |
||||
|
|
||||
|
var filterConditions = JsonSerializer.Deserialize<List<Filter>>(jsonFilter); |
||||
|
return filterConditions.ToLambda<T>(); |
||||
|
} |
||||
|
|
||||
|
public static Expression<Func<T, bool>> ToLambda<T>(this Filter filter) |
||||
|
{ |
||||
|
var filterConditions = new List<Filter> { filter }; |
||||
|
return filterConditions.ToLambda<T>(); |
||||
|
} |
||||
|
|
||||
|
public static Expression<Func<T, bool>> ToLambda<T>(this ICollection<Filter> filterConditionList) |
||||
|
{ |
||||
|
Expression<Func<T, bool>> condition = null; |
||||
|
try |
||||
|
{ |
||||
|
if (!filterConditionList.Any()) |
||||
|
{ |
||||
|
//创建默认表达式
|
||||
|
return p => true; |
||||
|
} |
||||
|
|
||||
|
foreach (var filterCondition in filterConditionList) |
||||
|
{ |
||||
|
var tempCondition = CreateLambda<T>(filterCondition); |
||||
|
if (condition == null) |
||||
|
{ |
||||
|
condition = tempCondition; |
||||
|
} |
||||
|
else |
||||
|
{ |
||||
|
condition = filterCondition.Logic switch |
||||
|
{ |
||||
|
"And" => condition.And(tempCondition), |
||||
|
"Or" => condition.Or(tempCondition), |
||||
|
_ => condition |
||||
|
}; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
catch (Exception ex) |
||||
|
{ |
||||
|
throw new Exception($"获取筛选条件异常:{ex.Message}"); |
||||
|
} |
||||
|
|
||||
|
return condition; |
||||
|
} |
||||
|
|
||||
|
private static Expression<Func<T, bool>> CreateLambda<T>(Filter filter) |
||||
|
{ |
||||
|
Expression<Func<T, bool>> expression = p => false; |
||||
|
try |
||||
|
{ |
||||
|
var parameter = Expression.Parameter(typeof(T), "p"); //创建参数p
|
||||
|
var member = Expression.PropertyOrField(parameter, filter.Column); //创建表达式中的属性或字段
|
||||
|
// var propertyType = member.Type; //取属性类型,常量constant按此类型进行转换
|
||||
|
//var constant = Expression.Constant(filterCondition.Value);//创建常数
|
||||
|
|
||||
|
ConstantExpression constant = null; |
||||
|
if (filter.Action != "In" && filter.Action != "NotIn") |
||||
|
{ |
||||
|
constant = CreateConstantExpression(member.Type, filter.Value); |
||||
|
} |
||||
|
|
||||
|
switch (filter.Action.ToLower()) |
||||
|
{ |
||||
|
case "==": |
||||
|
expression = Expression.Lambda<Func<T, bool>>(Expression.Equal(member, constant), parameter); |
||||
|
break; |
||||
|
|
||||
|
case "!=": |
||||
|
expression = Expression.Lambda<Func<T, bool>>(Expression.NotEqual(member, constant), parameter); |
||||
|
break; |
||||
|
|
||||
|
case ">": |
||||
|
expression = Expression.Lambda<Func<T, bool>>(Expression.GreaterThan(member, constant), parameter); |
||||
|
break; |
||||
|
|
||||
|
case "<": |
||||
|
expression = Expression.Lambda<Func<T, bool>>(Expression.LessThan(member, constant), parameter); |
||||
|
break; |
||||
|
|
||||
|
case ">=": |
||||
|
expression = Expression.Lambda<Func<T, bool>>(Expression.GreaterThanOrEqual(member, constant), parameter); |
||||
|
break; |
||||
|
|
||||
|
case "<=": |
||||
|
expression = Expression.Lambda<Func<T, bool>>(Expression.LessThanOrEqual(member, constant), parameter); |
||||
|
break; |
||||
|
|
||||
|
case "like": |
||||
|
expression = GetExpressionLikeMethod<T>("Contains", filter); |
||||
|
break; |
||||
|
|
||||
|
case "notlike": |
||||
|
expression = GetExpressionNotLikeMethod<T>("Contains", filter); |
||||
|
break; |
||||
|
|
||||
|
case "in": |
||||
|
expression = GetExpressionInMethod<T>("Contains", member.Type, filter); |
||||
|
break; |
||||
|
|
||||
|
case "notin": |
||||
|
expression = GetExpressionNotInMethod<T>("Contains", member.Type, filter); |
||||
|
break; |
||||
|
|
||||
|
default: |
||||
|
break; |
||||
|
} |
||||
|
} |
||||
|
catch (Exception ex) |
||||
|
{ |
||||
|
throw new Exception(ex.Message); |
||||
|
} |
||||
|
|
||||
|
return expression; |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
///
|
||||
|
/// </summary>
|
||||
|
/// <param name="propertyType"></param>
|
||||
|
/// <param name="value"></param>
|
||||
|
/// <returns></returns>
|
||||
|
private static ConstantExpression CreateConstantExpression(Type propertyType, string value) |
||||
|
{ |
||||
|
ConstantExpression constant; |
||||
|
try |
||||
|
{ |
||||
|
if (propertyType.IsGenericType && |
||||
|
propertyType.GetGenericTypeDefinition() == typeof(Nullable<>)) |
||||
|
{ |
||||
|
var objValue = Convert.ChangeType(value, propertyType.GetGenericArguments()[0], CultureInfo.InvariantCulture); |
||||
|
constant = Expression.Constant(objValue); |
||||
|
} |
||||
|
else if (propertyType.IsEnum) |
||||
|
{ |
||||
|
var enumValue = (Enum)Enum.Parse(propertyType, value, true); |
||||
|
constant = Expression.Constant(enumValue); |
||||
|
} |
||||
|
else |
||||
|
{ |
||||
|
constant = propertyType.Name switch |
||||
|
{ |
||||
|
"Guid" => Expression.Constant(Guid.Parse(value)), |
||||
|
_ => Expression.Constant(Convert.ChangeType(value, propertyType, CultureInfo.InvariantCulture)) |
||||
|
}; |
||||
|
} |
||||
|
} |
||||
|
catch (Exception ex) |
||||
|
{ |
||||
|
throw new Exception($"获取ConstantExpression异常:{ex.Message}"); |
||||
|
} |
||||
|
|
||||
|
return constant; |
||||
|
} |
||||
|
|
||||
|
private static Expression<Func<T, bool>> GetExpressionLikeMethod<T>(string methodName, Filter filter) |
||||
|
{ |
||||
|
var parameterExpression = Expression.Parameter(typeof(T), "p"); |
||||
|
// MethodCallExpression methodExpression = GetMethodExpression(methodName, filterCondition.Column, filterCondition.Value, parameterExpression);
|
||||
|
var methodExpression = GetMethodExpression(methodName, filter.Column, filter.Value, |
||||
|
parameterExpression); |
||||
|
return Expression.Lambda<Func<T, bool>>(methodExpression, parameterExpression); |
||||
|
} |
||||
|
|
||||
|
private static Expression<Func<T, bool>> GetExpressionNotLikeMethod<T>(string methodName, Filter filter) |
||||
|
{ |
||||
|
var parameterExpression = Expression.Parameter(typeof(T), "p"); |
||||
|
var methodExpression = GetMethodExpression(methodName, filter.Column, filter.Value, |
||||
|
parameterExpression); |
||||
|
var notMethodExpression = Expression.Not(methodExpression); |
||||
|
return Expression.Lambda<Func<T, bool>>(notMethodExpression, parameterExpression); |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// 生成guidList.Contains(p=>p.GUId);
|
||||
|
/// 除String类型,其他类型涉及到类型转换.如GUID
|
||||
|
/// </summary>
|
||||
|
/// <typeparam name="T"></typeparam>
|
||||
|
/// <param name="methodName">Contains</param>
|
||||
|
/// <param name="propertyType">PropertyType/typeof(GUId)</param>
|
||||
|
/// <param name="filter">PropertyName/PropertyValue</param>
|
||||
|
/// <returns></returns>
|
||||
|
private static Expression<Func<T, bool>> GetExpressionInMethod<T>(string methodName, Type propertyType, Filter filter) |
||||
|
{ |
||||
|
var parameterExpression = Expression.Parameter(typeof(T), "p"); |
||||
|
Type lstType = typeof(List<>).MakeGenericType(propertyType); |
||||
|
|
||||
|
//转换枚举
|
||||
|
//if (propertyType.IsEnum)
|
||||
|
//{
|
||||
|
// var valueArrayStrings = JsonSerializer.Deserialize<List<string>>(filter.Value);
|
||||
|
// List<object> newValues = new List<object>();
|
||||
|
|
||||
|
// var enumValues = propertyType.GetEnumValues();
|
||||
|
|
||||
|
// foreach (var valueArray in valueArrayStrings)
|
||||
|
// {
|
||||
|
// foreach (var enumValue in enumValues)
|
||||
|
// {
|
||||
|
// if (enumValue.ToString() == valueArray)
|
||||
|
// {
|
||||
|
// newValues.Add(enumValue);
|
||||
|
// break;
|
||||
|
// }
|
||||
|
// }
|
||||
|
// }
|
||||
|
// var newValue = JsonSerializer.Serialize(newValues);
|
||||
|
// filter.Value = newValue;
|
||||
|
//}
|
||||
|
|
||||
|
object propertyValue = JsonSerializer.Deserialize(filter.Value, lstType); |
||||
|
if (propertyValue != null) |
||||
|
{ |
||||
|
var methodExpression = GetListMethodExpression(methodName, propertyType, filter.Column, propertyValue, parameterExpression); |
||||
|
var expression = Expression.Lambda<Func<T, bool>>(methodExpression, parameterExpression); |
||||
|
return expression; |
||||
|
} |
||||
|
else |
||||
|
{ |
||||
|
return p => false; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
private static Expression<Func<T, bool>> GetExpressionNotInMethod<T>(string methodName, Type propertyType, Filter filter) |
||||
|
{ |
||||
|
var parameterExpression = Expression.Parameter(typeof(T), "p"); |
||||
|
Type lstType = typeof(List<>).MakeGenericType(propertyType); |
||||
|
object propertyValue = JsonSerializer.Deserialize(filter.Value, lstType); |
||||
|
if (propertyValue != null) |
||||
|
{ |
||||
|
var methodExpression = GetListMethodExpression(methodName, propertyType, filter.Column, propertyValue, parameterExpression); |
||||
|
var notMethodExpression = Expression.Not(methodExpression); |
||||
|
return Expression.Lambda<Func<T, bool>>(notMethodExpression, parameterExpression); |
||||
|
} |
||||
|
else |
||||
|
{ |
||||
|
return p => false; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
private static MethodCallExpression GetListMethodExpression(string methodName, Type propertyType, string propertyName, object propertyValue, ParameterExpression parameterExpression) |
||||
|
{ |
||||
|
var propertyExpression = Expression.Property(parameterExpression, propertyName); //p.GUID
|
||||
|
Type type = typeof(List<>).MakeGenericType(propertyType); |
||||
|
var method = type.GetMethod(methodName);//获取 List.Contains()
|
||||
|
var someValue = Expression.Constant(propertyValue);//Value
|
||||
|
return Expression.Call(someValue, method, propertyExpression); |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// 生成类似于p=>p.Code.Contains("xxx");的lambda表达式
|
||||
|
/// parameterExpression标识p,propertyName表示values,propertyValue表示"Code",methodName表示Contains
|
||||
|
/// 仅处理p的属性类型为string这种情况
|
||||
|
/// </summary>
|
||||
|
/// <param name="methodName"></param>
|
||||
|
/// <param name="propertyName"></param>
|
||||
|
/// <param name="propertyValue"></param>
|
||||
|
/// <param name="parameterExpression"></param>
|
||||
|
/// <returns></returns>
|
||||
|
private static MethodCallExpression GetMethodExpression(string methodName, string propertyName, |
||||
|
string propertyValue, ParameterExpression parameterExpression) |
||||
|
{ |
||||
|
var propertyExpression = Expression.Property(parameterExpression, propertyName); |
||||
|
var method = typeof(string).GetMethod(methodName, new[] { typeof(string) }); |
||||
|
var someValue = Expression.Constant(propertyValue, typeof(string)); |
||||
|
return Expression.Call(propertyExpression, method, someValue); |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// 默认True条件
|
||||
|
/// </summary>
|
||||
|
/// <typeparam name="T"></typeparam>
|
||||
|
/// <returns></returns>
|
||||
|
public static Expression<Func<T, bool>> True<T>() |
||||
|
{ |
||||
|
return f => true; |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// 默认False条件
|
||||
|
/// </summary>
|
||||
|
/// <typeparam name="T"></typeparam>
|
||||
|
/// <returns></returns>
|
||||
|
public static Expression<Func<T, bool>> False<T>() |
||||
|
{ |
||||
|
return f => false; |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// 拼接 OR 条件
|
||||
|
/// </summary>
|
||||
|
/// <typeparam name="T"></typeparam>
|
||||
|
/// <param name="exp"></param>
|
||||
|
/// <param name="condition"></param>
|
||||
|
/// <returns></returns>
|
||||
|
private static Expression<Func<T, bool>> Or<T>(this Expression<Func<T, bool>> exp, Expression<Func<T, bool>> condition) |
||||
|
{ |
||||
|
var inv = Expression.Invoke(condition, exp.Parameters); |
||||
|
return Expression.Lambda<Func<T, bool>>(Expression.Or(exp.Body, inv), exp.Parameters); |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// 拼接And条件
|
||||
|
/// </summary>
|
||||
|
/// <typeparam name="T"></typeparam>
|
||||
|
/// <param name="exp"></param>
|
||||
|
/// <param name="condition"></param>
|
||||
|
/// <returns></returns>
|
||||
|
private static Expression<Func<T, bool>> And<T>(this Expression<Func<T, bool>> exp, Expression<Func<T, bool>> condition) |
||||
|
{ |
||||
|
var inv = Expression.Invoke(condition, exp.Parameters); |
||||
|
return Expression.Lambda<Func<T, bool>>(Expression.And(exp.Body, inv), exp.Parameters); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
} |
@ -0,0 +1,23 @@ |
|||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
using System.Linq; |
||||
|
using System.Text; |
||||
|
using System.Threading.Tasks; |
||||
|
|
||||
|
namespace Wood.Util.Filters |
||||
|
{ |
||||
|
public class RequestInputBase |
||||
|
{ |
||||
|
public int pageNumber { get; set; } |
||||
|
|
||||
|
public int pageSize { get; set; } |
||||
|
|
||||
|
public string sortBy { get; set; } |
||||
|
|
||||
|
public bool isAscending { get; set; } |
||||
|
/// <summary>
|
||||
|
/// 条件
|
||||
|
/// </summary>
|
||||
|
public Condition Condition { get; set; } = new(); |
||||
|
} |
||||
|
} |
Loading…
Reference in new issue