You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

EF通用分页仓储方法调试:按类型处理条件过滤遇阻

解决方案:EF泛型仓储实现动态过滤(按类型判断是否应用过滤)

你的核心需求是仅当过滤参数符合有效条件时,才将对应的过滤规则应用到EF查询中(比如字符串非空、Guid非Empty等)。下面是针对这个需求的完整实现方案,解决你之前解析Expression时的问题:

关键思路

  1. 写一个通用方法判断过滤值是否"有效",决定是否应用该过滤条件;
  2. 解析过滤表达式,提取要比较的值和对应属性类型;
  3. 在仓储方法中,仅对有效过滤值对应的表达式执行Where操作。

完整实现代码

1. 辅助方法:判断过滤值是否有效

private bool IsFilterValueValid(object value, Type propertyType)
{
    if (value == null)
        return false;

    // 字符串类型:非null且非空/空白时才过滤
    if (propertyType == typeof(string))
    {
        return !string.IsNullOrWhiteSpace((string)value);
    }
    // Guid类型:不等于Guid.Empty时才过滤
    else if (propertyType == typeof(Guid))
    {
        return (Guid)value != Guid.Empty;
    }
    // 可空值类型(如int?、DateTime?):有值时才过滤
    else if (Nullable.GetUnderlyingType(propertyType) != null)
    {
        return ((System.Nullable)value).HasValue;
    }
    // 基础值类型(如int、DateTime):默认全部过滤(可根据业务调整)
    else if (propertyType.IsValueType)
    {
        return true;
    }
    // 其他引用类型:非null时才过滤
    else
    {
        return value != null;
    }
}

2. 辅助方法:解析过滤表达式,提取值和属性类型

private (object Value, Type PropertyType) GetFilterInfo(Expression<Func<TEntity, bool>> filter)
{
    // 处理二元表达式(如x => x.Name == "张三"、x => x.Id != Guid.Empty)
    if (filter.Body is BinaryExpression binaryExpr)
    {
        MemberExpression propertyExpr = null;
        Expression valueExpr = null;

        // 匹配左属性右值的情况
        if (binaryExpr.Left is MemberExpression leftMember)
        {
            propertyExpr = leftMember;
            valueExpr = binaryExpr.Right;
        }
        // 兼容右属性左值的特殊情况(如x => "张三" == x.Name)
        else if (binaryExpr.Right is MemberExpression rightMember)
        {
            propertyExpr = rightMember;
            valueExpr = binaryExpr.Left;
        }

        if (propertyExpr != null && valueExpr != null)
        {
            var propertyType = propertyExpr.Type;
            object value;

            // 处理常量值(如硬编码的字符串、Guid.Empty)
            if (valueExpr is ConstantExpression constantExpr)
            {
                value = constantExpr.Value;
            }
            // 处理变量引用(如传入的参数变量)
            else
            {
                var valueFunc = Expression.Lambda(valueExpr).Compile();
                value = valueFunc.DynamicInvoke();
            }

            return (value, propertyType);
        }
    }

    // 处理布尔属性直接作为过滤条件的情况(如x => x.IsActive)
    if (filter.Body is MemberExpression boolMember && boolMember.Type == typeof(bool))
    {
        return (null, typeof(bool));
    }

    // 默认情况:视为有效过滤条件
    return (null, typeof(object));
}

3. 修改后的泛型仓储方法

public virtual async Task<PageFilter<TEntity>> GetWithFilterAndPagination(
    BaseRequestFilter pagination,
    List<Expression<Func<TEntity, object>>> includes,
    List<Expression<Func<TEntity, bool>>> filters)
{
    try
    {
        using (var dbContext = IntegramillDbContextFactory.Create())
        {
            var query = dbContext.Set<TEntity>().AsQueryable();

            // 处理Include关联查询
            if (includes != null && includes.Any())
            {
                foreach (var include in includes)
                {
                    query = query.Include(include);
                }
            }

            // 处理过滤条件:仅应用有效过滤规则
            if (filters != null && filters.Any())
            {
                foreach (var filter in filters)
                {
                    var (filterValue, propertyType) = GetFilterInfo(filter);
                    // 布尔属性直接应用过滤
                    if (propertyType == typeof(bool))
                    {
                        query = query.Where(filter);
                    }
                    // 其他类型仅在值有效时应用
                    else if (IsFilterValueValid(filterValue, propertyType))
                    {
                        query = query.Where(filter);
                    }
                }
            }

            // 异步获取总条数
            var totalCount = await query.CountAsync();

            // 处理分页:兼容Offset为null的情况
            var skip = pagination.Offset ?? 0;
            if (skip > 0)
                query = query.Skip((int)skip);

            if (pagination.Take > 0)
                query = query.Take(pagination.Take);

            // 异步获取数据列表
            var data = await query.ToListAsync();

            return new PageFilter<TEntity>(data, totalCount);
        }
    }
    catch (Exception e)
    {
        Log.Error(e, "<{EventoId}> - Erro ao CONSULTAR " + typeof(TEntity).Name, "RepositoryError");
        throw;
    }
}

注意事项

  • 该实现支持常见类型的过滤判断,若有特殊类型(如枚举、自定义值类型),可扩展IsFilterValueValid方法;
  • 对于复杂过滤表达式(如x => x.Name.Contains("xxx")),当前逻辑会直接视为有效条件应用,若需针对这类表达式做判断,可扩展GetFilterInfo的解析逻辑;
  • 所有EF操作均使用异步API(CountAsync、ToListAsync),符合异步方法的设计规范;
  • 处理了Offset为null的边界情况,默认跳过0条数据。

内容的提问来源于stack exchange,提问作者Herik Sarmento

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.01 15:02:03