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)

处理流程:

  1. 为每个实体类型创建参数表达式(如 x, y, z
  2. 遍历请求参数的所有属性,查找带有 QueryFilterAttribute 的属性
  3. 根据特性配置生成对应的条件表达式
  4. AND 操作符连接所有条件
  5. 返回完整的表达式树

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"))

性能优化

  1. 缓存机制:使用 ConcurrentDictionary 缓存属性的特性信息
  2. 懒加载:反射方法信息使用 Lazy<T> 延迟加载
  3. 方法缓存:缓存 Enumerable.Contains 等常用方法

特色功能

  1. 多表支持:支持最多5个实体类型的联合查询
  2. 灵活的条件控制:通过 FilterCondition 精确控制何时应用过滤条件
  3. 丰富的比较操作:支持各种比较操作符和特殊场景处理
  4. 类型安全:通过表达式树保证类型安全
  5. 高性能:生成的表达式树可以被 EF Core 等 ORM 直接转换为 SQL

这个类是一个非常实用的工具,可以大大简化动态查询条件的构建,特别适合用于构建灵活的搜索和过滤功能。

评论加载中...