using System.Linq.Expressions;
|
|
namespace CmsQueryExtensions.Extension
|
{
|
internal class ParameterRebinder : ExpressionVisitor
|
{
|
private readonly Dictionary<ParameterExpression, ParameterExpression> map;
|
public ParameterRebinder(Dictionary<ParameterExpression, ParameterExpression> map)
|
{
|
this.map = map ?? new Dictionary<ParameterExpression, ParameterExpression>();
|
}
|
public static Expression ReplaceParameters(Dictionary<ParameterExpression, ParameterExpression> map, Expression exp)
|
{
|
return new ParameterRebinder(map).Visit(exp);
|
}
|
protected override Expression VisitParameter(ParameterExpression p)
|
{
|
ParameterExpression replacement;
|
if (map.TryGetValue(p, out replacement))
|
{
|
p = replacement;
|
}
|
return base.VisitParameter(p);
|
}
|
}
|
|
internal static class PredicateExtensions
|
{
|
public static Expression<Func<T, bool>> True<T>() { return f => true; }
|
public static Expression<Func<T, bool>> False<T>() { return f => false; }
|
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)
|
var 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
|
var 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);
|
}
|
|
public static Expression<Func<T, bool>> And<T>(this Expression<Func<T, bool>> first, Expression<Func<T, bool>> second)
|
{
|
return first.Compose(second, Expression.And);
|
}
|
|
public static Expression<Func<T, bool>> Or<T>(this Expression<Func<T, bool>> first, Expression<Func<T, bool>> second)
|
{
|
return first.Compose(second, Expression.Or);
|
}
|
|
|
/// <summary>
|
/// 拼接成 c.Name.contains("1111")||c.Name.Contains("2222")||c.Name.Contains("3333")) 形式
|
/// </summary>
|
/// <typeparam name="T"></typeparam>
|
/// <param name="options"></param>
|
/// <param name="fieldName"></param>
|
/// <returns></returns>
|
public static Expression<Func<T, bool>> GetConditionExpression<T>(string[] options, string fieldName)
|
{
|
ParameterExpression left = Expression.Parameter(typeof(T), "c");//c=>
|
Expression expression = Expression.Constant(false);
|
foreach (var optionName in options)
|
{
|
Expression right = Expression.Call
|
(
|
Expression.Property(left, typeof(T).GetProperty(fieldName)), //c.DataSourceName
|
typeof(string).GetMethod("Contains", new Type[] { typeof(string) }),// 反射使用.Contains()方法
|
Expression.Constant(optionName) // .Contains(optionName)
|
);
|
expression = Expression.Or(right, expression);//c.DataSourceName.contain("") || c.DataSourceName.contain("")
|
}
|
Expression<Func<T, bool>> finalExpression
|
= Expression.Lambda<Func<T, bool>>(expression, new ParameterExpression[] { left });
|
return finalExpression;
|
}
|
|
///// <summary>
|
///// (模糊查询)拼接成 c.Name.contains("1111")||c.Code.Contains("1111")||c.Address.Contains("1111")) 形式
|
///// </summary>
|
///// <typeparam name="T"></typeparam>
|
///// <param name="options"></param>
|
///// <param name="fieldName"></param>
|
///// <returns></returns>
|
//public static Expression<Func<T, bool>> GetConditionExpressionForFuzzyQuery<T>(string[] fieldNames, string fieldValue)
|
//{
|
// try
|
// {
|
// ParameterExpression left = Expression.Parameter(typeof(T), "c");//c=>
|
// Expression expression = Expression.Constant(true);//修改为true,解决公共模糊查询的问题
|
// foreach (var fieldName in fieldNames)
|
// {
|
// try
|
// {
|
// Expression right = Expression.Call
|
// (
|
// Expression.Property(left, typeof(T).GetProperty(fieldName)), //c.DataSourceName
|
// typeof(string).GetMethod("Contains", new Type[] { typeof(string) }),// 反射使用.Contains()方法
|
// Expression.Constant(fieldValue) // .Contains(fieldValue)
|
// );
|
// expression = Expression.Or(right, expression);//c.AAA.contain("") || c.BBB.contain("")
|
// }
|
// catch (Exception ex)
|
// {
|
// throw new Exception($"参数{fieldName}匹配关键字查询时失败:" + ex.Message);
|
// }
|
// }
|
// Expression<Func<T, bool>> finalExpression
|
// = Expression.Lambda<Func<T, bool>>(expression, new ParameterExpression[] { left });
|
// return finalExpression;
|
// }
|
// catch (Exception)
|
// {
|
// throw;
|
// }
|
//}
|
|
|
/// <summary>
|
/// (模糊查询)拼接成 c.Name.contains("1111")||c.Code.Contains("1111")||c.Address.Contains("1111")) 形式
|
/// </summary>
|
/// <typeparam name="T"></typeparam>
|
/// <param name="options"></param>
|
/// <param name="fieldName"></param>
|
/// <returns></returns>
|
public static Expression<Func<T, bool>> GetConditionExpressionForFuzzyQuery<T>(string[] fieldNames, string fieldValue)
|
{
|
if (fieldNames == null || fieldNames.Length == 0)
|
{
|
throw new ArgumentException("至少需要指定一个字段名", nameof(fieldNames));
|
}
|
|
if (string.IsNullOrEmpty(fieldValue))
|
{
|
// 空值查询返回总是返回false的表达式
|
var parameter2 = Expression.Parameter(typeof(T), "c");
|
return Expression.Lambda<Func<T, bool>>(Expression.Constant(false), parameter2);
|
}
|
|
ParameterExpression parameter = Expression.Parameter(typeof(T), "c");
|
Expression? expression = null;
|
|
foreach (var fieldName in fieldNames)
|
{
|
try
|
{
|
var propertyInfo = typeof(T).GetProperty(fieldName);
|
|
if (propertyInfo == null)
|
{
|
throw new ArgumentException($"类型 {typeof(T).Name} 不包含属性 {fieldName}");
|
}
|
|
if (propertyInfo.PropertyType != typeof(string))
|
{
|
throw new ArgumentException($"属性 {fieldName} 不是字符串类型");
|
}
|
|
var propertyAccess = Expression.Property(parameter, propertyInfo);
|
var containsMethod = typeof(string).GetMethod("Contains", new[] { typeof(string) });
|
var searchExpression = Expression.Call(propertyAccess, containsMethod!, Expression.Constant(fieldValue));
|
|
expression = expression == null
|
? searchExpression
|
: Expression.OrElse(expression, searchExpression);
|
}
|
catch (Exception ex)
|
{
|
throw new InvalidOperationException($"处理字段 {fieldName} 时出错", ex);
|
}
|
}
|
|
if (expression == null)
|
{
|
// 如果所有字段都无效,返回总是返回false的表达式
|
return Expression.Lambda<Func<T, bool>>(Expression.Constant(false), parameter);
|
}
|
|
return Expression.Lambda<Func<T, bool>>(expression, parameter);
|
}
|
|
/// <summary>
|
/// (精准查询)拼接成 c.Name.equals("1111")||c.Code.equals("1111")||c.Address.equals("1111")) 形式
|
/// </summary>
|
/// <typeparam name="T"></typeparam>
|
/// <param name="options"></param>
|
/// <param name="fieldName"></param>
|
/// <returns></returns>
|
public static Expression<Func<T, bool>> GetConditionExpressionForPreciseQuery<T>(string[] fieldNames, string fieldValue)
|
{
|
ParameterExpression left = Expression.Parameter(typeof(T), "c");//c=>
|
Expression expression = Expression.Constant(false);
|
foreach (var fieldName in fieldNames)
|
{
|
Expression right = Expression.Call
|
(
|
Expression.Property(left, typeof(T).GetProperty(fieldName)), //c.DataSourceName
|
typeof(string).GetMethod("Equals", new Type[] { typeof(string) }),// 反射使用.Equals()方法
|
Expression.Constant(fieldValue) // .Equals(fieldValue)
|
);
|
expression = Expression.Or(right, expression);//c.AAA.equals("") || c.BBB.equals("")
|
}
|
Expression<Func<T, bool>> finalExpression
|
= Expression.Lambda<Func<T, bool>>(expression, new ParameterExpression[] { left });
|
return finalExpression;
|
}
|
|
|
public static Expression<Func<T, bool>> GetConditionExpressionForHighFieldByAnd<T>(List<HighSearchModel> hsmList)
|
{
|
var whereHelper = new WhereHelper<T>();
|
foreach (var field in hsmList)
|
{
|
switch (field.filterMode)
|
{
|
case SearchFilterModeEnum.不等于:
|
whereHelper.NotEqual(field.fieldName, field.fieldValue);
|
break;
|
case SearchFilterModeEnum.大于:
|
whereHelper.GreaterThan(field.fieldName, field.fieldValue);
|
break;
|
case SearchFilterModeEnum.大于等于:
|
whereHelper.GreaterThanOrEqual(field.fieldName, field.fieldValue);
|
break;
|
case SearchFilterModeEnum.小于:
|
whereHelper.LessThan(field.fieldName, field.fieldValue);
|
break;
|
case SearchFilterModeEnum.小于等于:
|
whereHelper.LessThanOrEqual(field.fieldName, field.fieldValue);
|
break;
|
case SearchFilterModeEnum.模糊查询:
|
whereHelper.Contains(field.fieldName, field.fieldValue);
|
break;
|
case SearchFilterModeEnum.精准查询:
|
whereHelper.Equal(field.fieldName, field.fieldValue);
|
break;
|
}
|
}
|
|
Expression<Func<T, bool>> finalExpression
|
= Expression.Lambda<Func<T, bool>>(whereHelper.filter, new ParameterExpression[] { whereHelper.param });
|
return finalExpression;
|
}
|
|
public static Expression<Func<T, bool>> GetConditionExpressionForHighFieldByAnd<T>(List<HighSearchForDateTimeRangeModel> hsmForDatetimeList)
|
{
|
var whereHelper = new WhereHelper<T>();
|
foreach (var field in hsmForDatetimeList)
|
{
|
whereHelper.GreaterThanOrEqual(field.fieldName, field.start_fieldValue);
|
whereHelper.LessThanOrEqual(field.fieldName, field.end_fieldValue);
|
}
|
Expression<Func<T, bool>> finalExpression
|
= Expression.Lambda<Func<T, bool>>(whereHelper.filter, new ParameterExpression[] { whereHelper.param });
|
return finalExpression;
|
}
|
|
/// <summary>
|
/// 日期范围OR连接
|
/// </summary>
|
/// <typeparam name="T"></typeparam>
|
/// <param name="hsmForDatetimeList"></param>
|
/// <returns></returns>
|
public static Expression<Func<T, bool>> GetConditionExpressionForHighDateTimeRangeFieldByOr<T>(List<HighSearchForDateTimeRangeModel> hsmForDatetimeList)
|
{
|
Expression<Func<T, bool>> finalExpression = null;
|
var whereHelper = new WhereHelper<T>();
|
foreach (var field in hsmForDatetimeList)
|
{
|
whereHelper.GreaterThanOrEqual(field.fieldName, field.start_fieldValue);
|
whereHelper.LessThanOrEqual(field.fieldName, field.end_fieldValue);
|
|
finalExpression
|
= Expression.Lambda<Func<T, bool>>(whereHelper.filter, new ParameterExpression[] { whereHelper.param });
|
|
finalExpression = finalExpression.Or(finalExpression);
|
}
|
|
return finalExpression;
|
}
|
}
|
|
|
|
}
|