【问题标题】:FilterByItems Method not working correctlyFilterByItems 方法无法正常工作
【发布时间】:2021-12-29 03:44:26
【问题描述】:

我正在构建一个过滤器并使用FilterByItems 方法比较两个数组(一个来自我的前端,一个来自我的数据库)。这一切都通过我前端的覆盖面板进行,用户可以在其中选择不同的人员类型,如成员、工人等等。所以我的问题是现在我有多个不想一起工作的人型悬停。如果我只有一个它可以正常工作,如果我添加第二个它只有在前端列表中具有相同的值时才有效。

正确的情况是: 前端面板一得到了数组中的成员,前端面板二得到了数组中的朋友。 表格显示了在其个人资料中使用这些类型保存的所有人员。

当前和错误的情况是: 面板 1 和面板 2 不使用不同的数组,并且仅在两者具有相同列表时才显示信息,例如都在位置 [0] 上获得成员

一般来说,它看起来像一个单独的查询和查询,并且当第二个面板加入它时,它会完全阻塞。所以这是我的代码(FilterByItems 方法在上面链接):

//The Filter
//Login
[HttpPost("filter/")]
public async Task<IActionResult> Filter([FromBody] Filter user)
{
    var baseQuery = _context.Personens.AsQueryable();
    //Personentyp 1 Dont works in combination with below
    if (user.personenTypFilter.Length > 0)
        baseQuery = baseQuery.FilterByItems(user.personenTypFilter, (m, k) => m.Personentypzuordnungens.Any(i => i.Personentyp.Bezeichnung.Contains(k)), true);
    ////Personentyp 2
    //if (user.personenTypFilter2.Length > 0)
    //    baseQuery = baseQuery.FilterByItems(user.personenTypFilter2, (m, k) => m.Personentypzuordnungens.Any(i => i.Personentyp.Bezeichnung.Contains(k)), true);
    //---------------------------------
    var result = await (baseQuery.Select(p => new
    {
        personId = p.PersonId,
        nachname = p.Nachname,
        vorname = p.Vorname,
        plz = p.Plz,
        firmBez = p.Firmenbezeichnung,
        ort = p.Ort,
        personentyp = p.Personentypzuordnungens.Select(i => new
        {
            personentypId = i.PersonentypId,
        }),
        aktuellePosition = p.AktuellePosition,
        taetigkeit = p.Tätigkeit,
        kernkompetenzen = p.Kernkompetenzen,
        datenReviewedZeitpunkt = p.DatenReviewedZeitpunkt,
    }).ToListAsync());
    return Ok(result);
}

这就是我在过滤器模型中声明变量的方式:

public string[] personenTypFilter { get; set; }
public string[] personenTypFilter2 { get; set; }

.CombineAnd(来自 cmets)的新问题

baseQuery = baseQuery.Where(
                //Characteristics
                character1Predicate.CombineOr(character1Predicate2).CombineOr(character1Predicate3)
                //Persontypes
                .CombineAnd(personType1Predicate.CombineOr(personType2Predicate).CombineOr(personType3Predicate)));

【问题讨论】:

  • 所以你需要示意图baseQuery.FilterByItems(user.personenTypFilter, ..,) || baseQuery.FilterByItems(user.personenTypFilter2, ..,) ?
  • 是的,我想是的。我也已经这样尝试过了,但出现错误:“ || 不能应用于 IQueryable 和 IQueryable 类型的操作数”
  • 当然不能。我需要改进FilterByItems - 这是我的职责。
  • 哦哈哈哇,那太好了!
  • 不是真的,它有PredicateBuilder 在这里可能会有所帮助,但我可以在没有这种依赖的情况下做到这一点。

标签: c# asp.net .net linq


【解决方案1】:

此函数是FilterByItems 的演变,并添加了额外的公共方法来生成谓词并将它们组合。

您可以通过以下方式在查询中使用新的扩展:

var baseQuery = _context.Personens.AsQueryable();

var predicate1 = baseQuery.GetItemsPredicate(ser.personenTypFilter, (m, k) => m.Personentypzuordnungens.Any(i => i.Personentyp.Bezeichnung.Contains(k)));
var predicate2 = baseQuery.GetItemsPredicate(user.personenTypFilter2, (m, k) => m.Personentypzuordnungens.Any(i => i.Personentyp.Bezeichnung.Contains(k)));

// filter by combined predicates
baseQuery = baseQuery.Where(predicate1.CombineOr(predicate2));

及实施:

public static class QueryableExtensions
{
    public static IQueryable<T> FilterByItems<T, TItem>(this IQueryable<T> query, IEnumerable<TItem> items,
        Expression<Func<T, TItem, bool>> filterPattern, bool isOr = true, bool emptyValue = true)
    {
        var filterLambda = query.GetItemsPredicate(items, filterPattern, isOr, emptyValue);

        return query.Where(filterLambda);
    }

    public static Expression<Func<T, bool>> GetItemsPredicate<T, TItem>(this IEnumerable<T> query, IEnumerable<TItem> items, Expression<Func<T, TItem, bool>> filterPattern, bool isOr = true, bool emptyValue = false)
    {
        Expression predicate = null;
        foreach (var item in items)
        {
            var itemExpr = Expression.Constant(item);
            var itemCondition = ExpressionReplacer.Replace(filterPattern.Body, filterPattern.Parameters[1], itemExpr);
            if (predicate == null)
                predicate = itemCondition;
            else
            {
                predicate = Expression.MakeBinary(isOr ? ExpressionType.OrElse : ExpressionType.AndAlso, predicate,
                    itemCondition);
            }
        }

        predicate ??= Expression.Constant(emptyValue);
        var filterLambda = Expression.Lambda<Func<T, bool>>(predicate, filterPattern.Parameters[0]);
        return filterLambda;
    }

    public static Expression<Func<T, bool>> CombineOr<T>(this Expression<Func<T, bool>> predicate1,
        Expression<Func<T, bool>> predicate2)
    {
        var parameter = predicate1.Parameters[0];
        var body = Expression.OrElse(predicate1.Body, ExpressionReplacer.GetBody(predicate2, parameter));
        return Expression.Lambda<Func<T, bool>>(body, parameter);
    }

    public static Expression<Func<T, bool>> CombineAnd<T>(this Expression<Func<T, bool>> predicate1,
        Expression<Func<T, bool>> predicate2)
    {
        var parameter = predicate1.Parameters[0];
        var body = Expression.AndAlso(predicate1.Body, ExpressionReplacer.GetBody(predicate2, parameter));
        return Expression.Lambda<Func<T, bool>>(body, parameter);
    }

    class ExpressionReplacer : ExpressionVisitor
    {
        readonly IDictionary<Expression, Expression> _replaceMap;

        public ExpressionReplacer(IDictionary<Expression, Expression> replaceMap)
        {
            _replaceMap = replaceMap ?? throw new ArgumentNullException(nameof(replaceMap));
        }

        public override Expression Visit(Expression node)
        {
            if (node != null && _replaceMap.TryGetValue(node, out var replacement))
                return replacement;
            return base.Visit(node);
        }

        public static Expression Replace(Expression expr, Expression toReplace, Expression toExpr)
        {
            return new ExpressionReplacer(new Dictionary<Expression, Expression> { { toReplace, toExpr } }).Visit(expr);
        }

        public static Expression Replace(Expression expr, IDictionary<Expression, Expression> replaceMap)
        {
            return new ExpressionReplacer(replaceMap).Visit(expr);
        }

        public static Expression GetBody(LambdaExpression lambda, params Expression[] toReplace)
        {
            if (lambda.Parameters.Count != toReplace.Length)
                throw new InvalidOperationException();

            return new ExpressionReplacer(Enumerable.Range(0, lambda.Parameters.Count)
                .ToDictionary(i => (Expression)lambda.Parameters[i], i => toReplace[i])).Visit(lambda.Body);
        }
    }
}

【讨论】:

  • 效果很好,你!干得好
  • 对此我还有一个问题。所以一切都很好,但我有另一个面板,其特征例如“友好”等等。所以我试图将这些与 combineOr 结合起来,然后 combineAnd 因为它是一个过滤器。所以它应该只显示所有快乐的人和成员,所以我现在的问题是它显示了所有快乐的人和所有成员的人,它没有结合这些。明白了(看我的帖子)。但它只返回 0 个结果,如何处理?
  • 不确定您的业务逻辑。使用ReadableExpressionsVisualizers 检查您生成的内容。
  • 由于即将出现的错误,下载了该工具并进行了一些谷歌搜索:当被调试者端不支持 BinaryFormatter 时,通过流传递给 UI 的对象被格式化为 JSON,请改为调用 GetDeserializableObject .似乎不再支持 BinaryFormatter?
  • 看起来像是所选目标框架的问题。也试试这个:zspitz/ExpressionTreeVisualizer
猜你喜欢
  • 2019-06-02
  • 2014-09-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-12-01
相关资源
最近更新 更多