首页 > 解决方案 > 包含多个关键字的条件的 Lambda/Linq

问题描述

我必须列出

  1. 带有评论字段的主列表
  2. 要搜索的关键字列表。

我想在每条记录的每个评论字段中搜索关键字,在 SQL 中如下所示

select * from MainList
where Comment like '%keyword1%'
or Comment like '%keyword2%'
... so on until the last keyword.

到目前为止,我已经看到了示例,但通常一次只针对单个关键字,例如LINQ 与非 lambda 用于任何包含

我想要的是一次在 MainList 中的每条记录中搜索我的任何关键字的任何实例。就像是:

var newList = MainList.Where(m => m.Comments.Contains(purposes))

我更喜欢使用 lambda 语法,但如果不可能,linq 也可以。

标签: c#linq

解决方案


添加了可以帮助生成此类谓词的扩展方法。用法很简单:

var newList = MainList
   .FilterByItems(keywords, (m, k) => m.Comments.Contains(k), true)
   .ToList();

和实施:

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)
    {
        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(false);
        var filterLambda = Expression.Lambda<Func<T, bool>>(predicate, filterPattern.Parameters[0]);

        return query.Where(filterLambda);
    }

    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 exp)
        {
            if (exp != null && _replaceMap.TryGetValue(exp, out var replacement))
                return replacement;
            return base.Visit(exp);
        }

        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);
        }
    }
}

推荐阅读