using System.Collections;
using System.Collections.Concurrent;
using System.Linq.Expressions;
using System.Reflection;
namespace Dpz.Core.Entity.Base.ExpressTreeQuery;
/// <summary>
/// 条件过滤表达式树生成器
/// 用于根据请求参数动态生成 LINQ 表达式树,实现灵活的查询条件构建
/// </summary>
public static class GenerateConditionFilter
{
/// <summary>
/// 默认属性值的标识符
/// 当 QueryFilterAttribute 的 PropertyValue 等于此值时,将使用属性自身的值作为比较值
/// </summary>
internal const string DefaultPropertyValue = "10001";
private static readonly ConcurrentDictionary<
PropertyInfo,
IEnumerable<QueryFilterAttribute>
> PropertyQueryFilterAttributesCache = new();
private static IEnumerable<QueryFilterAttribute> GetQueryFilterAttributes(PropertyInfo property)
{
return PropertyQueryFilterAttributesCache.GetOrAdd(
property,
p => p.GetCustomAttributes<QueryFilterAttribute>()
);
}
/// <summary>
/// 为单个实体类型生成条件表达式树
/// </summary>
/// <typeparam name="T">实体类型</typeparam>
/// <typeparam name="TRequest">请求参数类型</typeparam>
/// <param name="request">请求参数实例</param>
/// <returns>条件表达式树,形如:x => x.Property1 == value1 && x.Property2 > value2</returns>
public static Expression<Func<T, bool>> GenerateConditionExpressionTree<T, TRequest>(
TRequest request
)
{
return GenerateConditionExpressionTree<Func<T, bool>, TRequest>(request, typeof(T));
}
/// <summary>
/// 为两个实体类型生成条件表达式树
/// </summary>
/// <typeparam name="T">第一个实体类型</typeparam>
/// <typeparam name="T2">第二个实体类型</typeparam>
/// <typeparam name="TRequest">请求参数类型</typeparam>
/// <param name="request">请求参数实例</param>
/// <returns>条件表达式树,形如:(x, y) => x.Property1 == value1 && y.Property2 > value2</returns>
public static Expression<Func<T, T2, bool>> GenerateConditionExpressionTree<T, T2, TRequest>(
TRequest request
)
{
return GenerateConditionExpressionTree<Func<T, T2, bool>, TRequest>(
request,
typeof(T),
typeof(T2)
);
}
/// <summary>
/// 为三个实体类型生成条件表达式树
/// </summary>
/// <typeparam name="T">第一个实体类型</typeparam>
/// <typeparam name="T2">第二个实体类型</typeparam>
/// <typeparam name="T3">第三个实体类型</typeparam>
/// <typeparam name="TRequest">请求参数类型</typeparam>
/// <param name="request">请求参数实例</param>
/// <returns>条件表达式树,形如:(x, y, z) => x.Property1 == value1 && y.Property2 > value2 && z.Property3 != value3</returns>
public static Expression<Func<T, T2, T3, bool>> GenerateConditionExpressionTree<
T,
T2,
T3,
TRequest
>(TRequest request)
{
return GenerateConditionExpressionTree<Func<T, T2, T3, bool>, TRequest>(
request,
typeof(T),
typeof(T2),
typeof(T3)
);
}
/// <summary>
/// 为四个实体类型生成条件表达式树
/// </summary>
/// <typeparam name="T">第一个实体类型</typeparam>
/// <typeparam name="T2">第二个实体类型</typeparam>
/// <typeparam name="T3">第三个实体类型</typeparam>
/// <typeparam name="T4">第四个实体类型</typeparam>
/// <typeparam name="TRequest">请求参数类型</typeparam>
/// <param name="request">请求参数实例</param>
/// <returns>
/// 条件表达式树,形如:
/// <![CDATA[(x, y, z, w) => x.Property1 == value1 && y.Property2 > value2 && z.Property3 != value3 && w.Property4 <= value4]]>
/// </returns>
public static Expression<Func<T, T2, T3, T4, bool>> GenerateConditionExpressionTree<
T,
T2,
T3,
T4,
TRequest
>(TRequest request)
{
return GenerateConditionExpressionTree<Func<T, T2, T3, T4, bool>, TRequest>(
request,
typeof(T),
typeof(T2),
typeof(T3),
typeof(T4)
);
}
/// <summary>
/// 为五个实体类型生成条件表达式树
/// </summary>
/// <typeparam name="T">第一个实体类型</typeparam>
/// <typeparam name="T2">第二个实体类型</typeparam>
/// <typeparam name="T3">第三个实体类型</typeparam>
/// <typeparam name="T4">第四个实体类型</typeparam>
/// <typeparam name="T5">第五个实体类型</typeparam>
/// <typeparam name="TRequest">请求参数类型</typeparam>
/// <param name="request">请求参数实例</param>
/// <returns>
/// 条件表达式树,形如:
/// <![CDATA[(x, y, z, w, v) => x.Property1 == value1 && y.Property2 > value2 && z.Property3 != value3 && w.Property4 <= value4 && v.Property5 >= value5]]>
/// </returns>
public static Expression<Func<T, T2, T3, T4, T5, bool>> GenerateConditionExpressionTree<
T,
T2,
T3,
T4,
T5,
TRequest
>(TRequest request)
{
return GenerateConditionExpressionTree<Func<T, T2, T3, T4, T5, bool>, TRequest>(
request,
typeof(T),
typeof(T2),
typeof(T3),
typeof(T4),
typeof(T5)
);
}
/// <summary>
/// 核心方法:根据请求参数和实体类型生成条件表达式树
/// </summary>
/// <typeparam name="TFunc">委托类型</typeparam>
/// <typeparam name="TRequest">请求参数类型</typeparam>
/// <param name="request">请求参数实例</param>
/// <param name="additionalTypes">实体类型数组</param>
/// <returns>条件表达式树</returns>
/// <remarks>
/// 处理流程:
/// 1. 为每个实体类型创建参数表达式
/// 2. 获取请求参数类型的所有属性,并处理带有 QueryFilterAttribute 特性的属性
/// 3. 根据属性的 QueryFilterAttribute 特性生成对应的条件表达式
/// 4. 将所有条件表达式用 AND 连接起来
/// 5. 如果没有生成任何条件表达式,则返回始终为 true 的表达式
/// </remarks>
private static Expression<TFunc> GenerateConditionExpressionTree<TFunc, TRequest>(
TRequest request,
params Type[] additionalTypes
)
where TFunc : Delegate
{
// 为每个实体类型创建参数表达式
var parameters = additionalTypes
.Select((x, index) => Expression.Parameter(x, $"__q{(index == 0 ? "" : index)}"))
.ToList();
// 获取请求参数类型的所有属性,并处理带有QueryFilterAttribute特性的属性
var queryFieldsExpression = PropertyAccessor
.GetProperties(typeof(TRequest))
.SelectMany(x =>
{
var attributes = GetQueryFilterAttributes(x);
var getter = PropertyAccessor.GetGetter<TRequest>(x.Name);
var value = getter?.Invoke(request);
return HandleField(
parameters,
GetPropertyInfoByAttr,
GetValueByAttr,
attributes,
value
);
// 根据特性获取对应的属性信息
PropertyInfo? GetPropertyInfoByAttr(QueryFilterAttribute attr) =>
PropertyAccessor.GetProperty(
(additionalTypes.Length == 1 ? additionalTypes[0] : attr.EntityType),
attr.PropertyName ?? x.Name
);
// 获取用于比较的值
object? GetValueByAttr(QueryFilterAttribute attr) =>
attr.PropertyValue?.Equals(DefaultPropertyValue) == true
? value
: attr.PropertyValue;
})
.ToList();
// 如果没有生成任何条件表达式,则返回始终为true的表达式
if (queryFieldsExpression.Count == 0)
{
return Expression.Lambda<TFunc>(Expression.Constant(true), parameters.ToArray());
}
// 将所有条件表达式用AND连接起来
var finalExpression = queryFieldsExpression.Aggregate(Expression.AndAlso);
return Expression.Lambda<TFunc>(finalExpression, parameters.ToArray());
}
/// <summary>
/// 处理单个字段的过滤条件,生成对应的表达式
/// </summary>
/// <param name="parameters">参数表达式列表</param>
/// <param name="propertyFunc">获取属性信息的函数</param>
/// <param name="valueFunc">获取比较值的函数</param>
/// <param name="attributes">查询过滤特性集合</param>
/// <param name="selfValue">属性自身的值</param>
/// <returns>生成的表达式集合</returns>
/// <remarks>
/// 处理流程:
/// 1. 遍历所有 QueryFilterAttribute 特性
/// 2. 获取对应的属性信息和比较值
/// 3. 根据 Comparison 和 FilterCondition 生成相应的表达式
/// 4. 处理特殊条件(如日期范围、false值包含null等)
/// </remarks>
private static IEnumerable<Expression> HandleField(
List<ParameterExpression> parameters,
Func<QueryFilterAttribute, PropertyInfo?> propertyFunc,
Func<QueryFilterAttribute, object?> valueFunc,
IEnumerable<QueryFilterAttribute> attributes,
object? selfValue
)
{
foreach (var attr in attributes)
{
// 检查是否应该跳过此条件
if (selfValue == null || ShouldSkip(selfValue, attr.Condition, attr.ConditionValue))
{
continue;
}
// 确定使用哪个参数表达式
var parameter =
parameters.Count == 1
? parameters[0]
: parameters.Find(x => x.Type == attr.EntityType);
if (parameter == null)
{
continue;
}
// 获取比较值
var value = valueFunc(attr);
// 处理多属性 OR 逻辑(PropertiesNames)
if (attr.PropertiesNames is { Length: > 0 })
{
foreach (
var expression1 in CreatePropertiesNamesComparisonExpression(
parameter,
attr,
value
)
)
{
yield return expression1;
}
continue;
}
// 处理单属性逻辑(PropertyName)
var singleProperty = propertyFunc(attr);
if (singleProperty == null)
{
continue;
}
var expression = CreateComparisonExpression(parameter, singleProperty, attr, value);
yield return expression;
}
}
/// <summary>
/// 创建多属性 OR 逻辑的比较表达式
/// </summary>
/// <param name="parameter">参数表达式</param>
/// <param name="attr">查询过滤特性</param>
/// <param name="value">比较值</param>
/// <returns>OR 连接的表达式集合</returns>
/// <exception cref="ArgumentNullException"></exception>
private static IEnumerable<Expression> CreatePropertiesNamesComparisonExpression(
ParameterExpression parameter,
QueryFilterAttribute attr,
object? value
)
{
if (attr.PropertiesNames == null || attr.PropertiesNames.Length == 0)
{
yield break;
}
// 确定实体类型:单实体直接用 parameter.Type,多实体用 attr.EntityType
var entityType = attr.EntityType ?? parameter.Type;
var orExpressions = attr
.PropertiesNames.Select(x => PropertyAccessor.GetProperty(entityType, x))
.OfType<PropertyInfo>()
.Select(property => CreateComparisonExpression(parameter, property, attr, value))
.ToList();
// 将所有表达式用 OR 连接
if (orExpressions.Count > 0)
{
yield return orExpressions.Aggregate(Expression.OrElse);
}
}
/// <summary>
/// 创建单个属性的比较表达式
/// </summary>
/// <param name="parameter">参数表达式</param>
/// <param name="property">属性信息</param>
/// <param name="attr">查询过滤特性</param>
/// <param name="value">比较值</param>
/// <returns>比较表达式,如果不应生成则返回 null</returns>
/// <remarks>
/// 调用此方法前,调用方应已通过 ShouldSkip 验证了请求参数的值
/// </remarks>
private static Expression CreateComparisonExpression(
ParameterExpression parameter,
PropertyInfo property,
QueryFilterAttribute attr,
object? value
)
{
// 创建成员访问表达式
Expression memberExpr = Expression.Property(parameter, property);
// 处理日期加一天的情况
if (attr.EndAddDay && value is DateTime end)
{
value = end.AddDays(1);
}
// 处理按天过滤的情况
if (attr.FilterInDay && value is DateTime filterDay)
{
var left = !IsNullableType(property.PropertyType)
? Expression.Convert(memberExpr, typeof(DateTime?))
: memberExpr;
return DateRangeFilter(left, filterDay);
}
// 处理false值包含null的情况
if (value is false && attr.FalseHasNull)
{
var right1 = Expression.Convert(Expression.Constant(value), property.PropertyType);
var right2 = Expression.Convert(Expression.Constant(null), property.PropertyType);
var equalComparison1 = Expression.Equal(memberExpr, right1);
var equalComparison2 = Expression.Equal(memberExpr, right2);
return Expression.OrElse(equalComparison1, equalComparison2);
}
// 创建右侧表达式
Expression right;
if (
attr.Comparison != Comparison.Contains
&& value != null
&& property.PropertyType != value.GetType()
)
{
right = Expression.Convert(Expression.Constant(value), property.PropertyType);
}
else
{
right = Expression.Constant(value);
}
// 根据比较方式生成不同的表达式
return attr.Comparison switch
{
Comparison.Equal => Expression.Equal(memberExpr, right),
Comparison.Gt => Expression.GreaterThan(memberExpr, right),
Comparison.GtOrEqual => Expression.GreaterThanOrEqual(memberExpr, right),
Comparison.Lt => Expression.LessThan(memberExpr, right),
Comparison.LtOrEqual => Expression.LessThanOrEqual(memberExpr, right),
Comparison.NotEqual => Expression.NotEqual(memberExpr, right),
Comparison.Contains => CreateContainsExpression(
memberExpr,
attr.Condition == FilterCondition.RightAny ? attr.ConditionValue : value,
attr.Condition
),
Comparison.SplitOrContains => CreateSplitOrContains(
memberExpr,
value,
attr.SplitOrContainsOtherSeparators
),
_ => throw new NotSupportedException($"Comparison '{attr.Comparison}' not supported."),
};
}
/// <summary>
/// 创建日期范围过滤表达式,过滤指定日期当天的数据
/// </summary>
/// <param name="left">左侧表达式(日期字段)</param>
/// <param name="filterDay">要过滤的日期</param>
/// <returns>日期范围过滤表达式,形如:<![CDATA[date >= start && date < end]]></returns>
private static BinaryExpression DateRangeFilter(Expression left, DateTime filterDay)
{
DateTime? start = filterDay.Date;
DateTime? end = start.Value.AddDays(1);
return Expression.AndAlso(
Expression.GreaterThanOrEqual(left, Expression.Constant(start, typeof(DateTime?))),
Expression.LessThan(left, Expression.Constant(end, typeof(DateTime?)))
);
}
/// <summary>
/// 字符串HashSet的Contains方法的懒加载引用
/// 用于优化字符串集合的包含关系检查
/// </summary>
private static readonly Lazy<MethodInfo> StringHashSetContainsMethod = new(() =>
typeof(HashSet<string>).GetMethod("Contains", BindingFlags.Public | BindingFlags.Instance)
?? throw new NotSupportedException("not supported 'Contains' method")
);
/// <summary>
/// 字符串Contains方法的缓存
/// 用于优化字符串的包含关系检查
/// </summary>
private static readonly Lazy<MethodInfo> StringContainsMethod = new(() =>
typeof(string).GetMethod("Contains", [typeof(string)])
?? throw new NotSupportedException("not supported string 'Contains' method")
);
/// <summary>
/// Enumerable.Contains方法的缓存
/// 用于优化集合的包含关系检查
/// Key: 元素类型
/// Value: 对应的 Contains 方法信息
/// </summary>
private static readonly ConcurrentDictionary<Type, MethodInfo> EnumerableContainsMethodCache =
new();
/// <summary>
/// 获取Enumerable.Contains方法
/// </summary>
/// <param name="elementType">集合元素类型</param>
/// <returns>Contains方法信息</returns>
/// <exception cref="NotSupportedException">当找不到对应的Contains方法时抛出</exception>
private static MethodInfo GetEnumerableContainsMethod(Type elementType)
{
return EnumerableContainsMethodCache.GetOrAdd(
elementType,
type =>
typeof(Enumerable)
.GetMethods()
.FirstOrDefault(m => m.Name == "Contains" && m.GetParameters().Length == 2)
?.MakeGenericMethod(type)
?? throw new NotSupportedException(
$"not supported Enumerable 'Contains' method for type {type}"
)
);
}
/// <summary>
/// 创建包含关系的表达式,支持字符串包含和集合包含
/// </summary>
/// <param name="memberExpr">成员表达式</param>
/// <param name="value">要检查的值</param>
/// <param name="condition">过滤条件</param>
/// <returns>包含关系的表达式</returns>
/// <remarks>
/// 支持以下情况:
/// 1. 字符串包含:生成 string.Contains 调用
/// 2. 集合包含:生成 Enumerable.Contains 调用
/// 3. 可空类型:自动处理可空类型的转换
/// </remarks>
private static Expression CreateContainsExpression(
Expression memberExpr,
object? value,
FilterCondition condition = FilterCondition.LeftAny
)
{
if (value is string)
{
return Expression.Call(
memberExpr,
StringContainsMethod.Value,
Expression.Constant(value)
);
}
if (condition is not (FilterCondition.LeftAny or FilterCondition.RightAny))
{
return Expression.Constant(false);
}
if (value is IEnumerable enumerable)
{
// 如果属性类型是可空类型,需要先获取其基础类型
var elementType = IsNullableType(memberExpr.Type)
? Nullable.GetUnderlyingType(memberExpr.Type)
: memberExpr.Type;
// 获取对应基础类型的 Contains 方法
var baseContainsMethod = GetEnumerableContainsMethod(elementType!);
// 如果属性是可空类型,需要先转换为非空类型
var convertedMemberExpr = IsNullableType(memberExpr.Type)
? Expression.Convert(memberExpr, elementType!)
: memberExpr;
return Expression.Call(
baseContainsMethod,
Expression.Constant(enumerable),
convertedMemberExpr
);
}
return Expression.Constant(false);
}
private static bool IsNullableType(Type type)
{
return Nullable.GetUnderlyingType(type) != null;
}
/// <summary>
/// 创建分割或包含表达式
/// 如果字符串不能被空格或其他分隔符分割,则执行模糊查询;否则执行IN查询
/// </summary>
/// <param name="memberExpr">成员表达式</param>
/// <param name="value">要检查的值</param>
/// <param name="splitOrContainsOtherSeparators">用于分隔字符串的除了空格的其他分隔符</param>
/// <returns>分割或包含表达式</returns>
/// <remarks>
/// 处理流程:
/// 1. 如果输入不是字符串或为空,返回false
/// 2. 使用空格和其他分隔符分割字符串
/// 3. 如果分割后只有一个值,执行模糊查询
/// 4. 否则,将分割后的值转换为HashSet,执行IN查询
/// </remarks>
private static Expression CreateSplitOrContains(
Expression memberExpr,
object? value,
char[]? splitOrContainsOtherSeparators
)
{
if (value is not string strValue || string.IsNullOrWhiteSpace(strValue))
{
return Expression.Constant(false);
}
const char splitChar = ' ';
if (splitOrContainsOtherSeparators is { Length: > 0 })
{
//如果有其他分隔符,则空格替换其他分隔符
foreach (var c in splitOrContainsOtherSeparators)
{
strValue = strValue.Replace(c, splitChar);
}
}
var splitValues = strValue.Split(splitChar);
if (!strValue.Contains(splitChar) && splitValues.Length <= 1)
{
return CreateContainsExpression(memberExpr, strValue);
}
var values = splitValues.Where(p => !string.IsNullOrWhiteSpace(p)).ToHashSet();
var valuesConstant = Expression.Constant(values);
return Expression.Call(
instance: valuesConstant,
method: StringHashSetContainsMethod.Value,
arguments: Expression.Convert(memberExpr, typeof(string))
);
}
/// <summary>
/// 根据不同的条件,判断是否应该跳过当前过滤条件
/// </summary>
/// <param name="value">要检查的值</param>
/// <param name="condition">过滤条件</param>
/// <param name="comparisonValue">比较值</param>
/// <returns>如果应该跳过,则返回true;否则返回false</returns>
/// <remarks>
/// 处理以下条件:
/// 1. NotNull:值为null时跳过
/// 2. NotNullOrEmpty:字符串为null或空时跳过
/// 3. NotNullOrWhiteSpace:字符串为null或空白时跳过
/// 4. LeftAny:集合为null或空时跳过
/// 5. RightAny:数组为null或空时跳过
/// 6. EqualValue/NotEqualValue:根据值是否相等决定是否跳过
/// 7. 比较操作符:根据比较结果决定是否跳过
/// </remarks>
private static bool ShouldSkip(
object? value,
FilterCondition condition,
object? comparisonValue
)
{
return condition switch
{
FilterCondition.NotNull => value == null,
FilterCondition.NotNullOrEmpty => value is not string str || string.IsNullOrEmpty(str),
FilterCondition.NotNullOrWhiteSpace => value is not string str
|| string.IsNullOrWhiteSpace(str),
FilterCondition.LeftAny => value is not ICollection collection || collection.Count == 0,
FilterCondition.RightAny => comparisonValue is not Array array || array.Length == 0,
FilterCondition.EqualValue => !AreEqual(value, comparisonValue),
FilterCondition.NotEqualValue => AreEqual(value, comparisonValue),
FilterCondition.GtValue
or FilterCondition.LtValue
or FilterCondition.GtOrEqualValue
or FilterCondition.LtOrEqualValue => OperatorInvoke(value, condition, comparisonValue)
!= true,
_ => false,
};
}
/// <summary>
/// 执行比较操作符,用于大于、小于等比较
/// </summary>
/// <param name="value">左侧值</param>
/// <param name="condition">比较条件</param>
/// <param name="conditionValue">右侧值</param>
/// <returns>比较结果,如果无法比较则返回null</returns>
/// <remarks>
/// 支持以下比较操作:
/// 1. GtValue:大于
/// 2. LtValue:小于
/// 3. GtOrEqualValue:大于等于
/// 4. LtOrEqualValue:小于等于
/// </remarks>
private static bool? OperatorInvoke(
object? value,
FilterCondition condition,
object? conditionValue
)
{
if (value == null || conditionValue == null)
{
return null;
}
if (value.GetType() != conditionValue.GetType())
{
return null;
}
Expression left = Expression.Constant(value);
Expression right;
var currentType = value.GetType();
if (currentType != conditionValue.GetType())
{
right = Expression.Convert(Expression.Constant(conditionValue), currentType);
}
else
{
right = Expression.Constant(conditionValue);
}
Expression<Func<bool>> initExpression = () => false;
Expression comparisonExpression = initExpression;
switch (condition)
{
// >
case FilterCondition.GtValue:
comparisonExpression = Expression.GreaterThan(left, right);
break;
// <
case FilterCondition.LtValue:
comparisonExpression = Expression.LessThan(left, right);
break;
// >=
case FilterCondition.GtOrEqualValue:
comparisonExpression = Expression.GreaterThanOrEqual(left, right);
break;
// <=
case FilterCondition.LtOrEqualValue:
comparisonExpression = Expression.LessThanOrEqual(left, right);
break;
}
if (comparisonExpression != initExpression)
{
return Expression.Lambda<Func<bool>>(comparisonExpression).Compile().Invoke();
}
return null;
}
/// <summary>
/// 判断两个对象是否相等
/// </summary>
/// <param name="value1">第一个对象</param>
/// <param name="value2">第二个对象</param>
/// <returns>如果相等则返回true,否则返回false</returns>
/// <remarks>
/// 处理规则:
/// 1. 如果两个值都为null,返回false
/// 2. 如果只有一个值为null,返回false
/// 3. 否则使用Equals方法比较
/// </remarks>
private static bool AreEqual(object? value1, object? value2)
{
//if (value1 == null && value2 == null) return true;
if (value1 == null || value2 == null)
{
return false;
}
return value1.Equals(value2);
}
}
⚠⚠ 以下内容为AI分析的结果,请根据实际情况进行判断。
这是一个用于动态生成 LINQ 表达式树的条件过滤器类,主要用于根据请求参数自动构建查询条件。以下是详细解释:
核心功能
这个类的主要作用是根据请求参数对象中带有 QueryFilterAttribute 特性的属性,动态生成 LINQ 表达式树,用于数据库查询的条件过滤。
主要组成部分
1. 公共方法 - 表达式树生成器
// 支持1-5个实体类型的表达式树生成
GenerateConditionExpressionTree<T, TRequest>(request)
GenerateConditionExpressionTree<T, T2, TRequest>(request)
// ... 最多支持5个实体类型
这些方法为不同数量的实体类型生成对应的表达式树,支持单表查询到多表联合查询。
2. 核心实现方法
private static Expression<TFunc> GenerateConditionExpressionTree<TFunc, TRequest>(
TRequest request, params Type[] additionalTypes)
处理流程:
- 为每个实体类型创建参数表达式(如
x,y,z) - 遍历请求参数的所有属性,查找带有
QueryFilterAttribute的属性 - 根据特性配置生成对应的条件表达式
- 用
AND操作符连接所有条件 - 返回完整的表达式树
3. 字段处理方法
private static IEnumerable<Expression> HandleField(...)
处理单个字段的过滤条件:
- 检查是否应该跳过该条件(基于
ShouldSkip方法) - 处理多属性 OR 逻辑(
PropertiesNames) - 处理单属性逻辑(
PropertyName)
4. 表达式创建方法
单属性比较表达式:
private static Expression CreateComparisonExpression(...)
支持多种比较操作:
- 基本比较:
=,>,>=,<,<=,!= - 包含操作:字符串包含、集合包含
- 特殊处理:日期范围过滤、null值处理等
包含关系表达式:
private static Expression CreateContainsExpression(...)
支持:
- 字符串包含:
string.Contains() - 集合包含:
Enumerable.Contains() - 可空类型的自动转换
5. 条件跳过逻辑
private static bool ShouldSkip(...)
根据 FilterCondition 枚举决定是否跳过某个条件:
NotNull:值为null时跳过NotNullOrEmpty:字符串为空时跳过LeftAny:集合为空时跳过EqualValue/NotEqualValue:根据值比较结果跳过- 等等...
使用示例
假设有一个请求类:
public class UserSearchRequest
{
[QueryFilter(Comparison = Comparison.Contains)]
public string? Name { get; set; }
[QueryFilter(Comparison = Comparison.GtOrEqual)]
public DateTime? CreateTime { get; set; }
[QueryFilter(PropertiesNames = new[] {"Email", "Phone"}, Comparison = Comparison.Contains)]
public string? Contact { get; set; }
}
调用:
var request = new UserSearchRequest
{
Name = "张三",
CreateTime = DateTime.Today,
Contact = "123"
};
var expression = GenerateConditionFilter
.GenerateConditionExpressionTree<User, UserSearchRequest>(request);
// 生成的表达式类似于:
// x => x.Name.Contains("张三") && x.CreateTime >= DateTime.Today && (x.Email.Contains("123") || x.Phone.Contains("123"))
性能优化
- 缓存机制:使用
ConcurrentDictionary缓存属性的特性信息 - 懒加载:反射方法信息使用
Lazy<T>延迟加载 - 方法缓存:缓存
Enumerable.Contains等常用方法
特色功能
- 多表支持:支持最多5个实体类型的联合查询
- 灵活的条件控制:通过
FilterCondition精确控制何时应用过滤条件 - 丰富的比较操作:支持各种比较操作符和特殊场景处理
- 类型安全:通过表达式树保证类型安全
- 高性能:生成的表达式树可以被 EF Core 等 ORM 直接转换为 SQL
这个类是一个非常实用的工具,可以大大简化动态查询条件的构建,特别适合用于构建灵活的搜索和过滤功能。
AI 正在分析代码…
评论加载中...