用于字符串的表达式生成器函数.包含和字符串[]

本文关键字:字符串 包含 函数 表达式 用于 | 更新日期: 2023-09-27 18:03:24

我很难创建一个表达式构建器函数来传递给NHibernate存储库的查询。

基本上我想要能够做的是从各种对象属性(字符串)建立一个查询,并比较它们的值在数组中的值。还可以添加其他查询语句

比如

public static Expression<Func<TElement, bool>> BuildOrExpression<TElement, TValue>
    (Dictionary<Expression<Func<TElement, TValue>>, IEnumerable<TValue>> expressionSet)
{
    List<Expression> newExpressions = new List<Expression>();
    foreach (var item in expressionSet)
    {
        if (null == item.Key) throw new ArgumentNullException("valueSelector");
        if (null == item.Value) throw new ArgumentNullException("values");
        ParameterExpression p = item.Key.Parameters.Single();
        if (!item.Value.Any()) return e => false;
        IEnumerable<Expression> expressions = item.Value
           .Select(value => (Expression)Expression.Equal(item.Key.Body, Expression.Constant(value, typeof(TValue))));
        Expression compExpression = expressions
            .Aggregate<Expression>((accumulate, equal) => Expression.OrElse(accumulate, equal));
        newExpressions.Add(Expression.Lambda<Func<TElement, bool>>(compExpression, p));
    }
    Expression accExpression = newExpressions
        .Aggregate<Expression>((accumulate, equal) => Expression.OrElse(accumulate, equal));
    return Expression.Lambda<Func<TElement, bool>>(accExpression);
}

但不是做Expression.Equal而是做String.Contains

欢迎任何帮助。顺便说一下,上面的代码没有经过测试。

用于字符串的表达式生成器函数.包含和字符串[]

您需要使用Expression.Call并传递Contains MethodInfo实例而不是Expression.Equal。像这样

IEnumerable<Expression> expressions = item.Value.Select(value => 
   (Expression)Expression.Call(item.Key.Body, 
   typeof(String).GetMethod("Contains"), 
   Expression.Constant(value, typeof(TValue))));

我能够克服表达式组合问题,但我不确定这是最好的解决方案。我使用了Vladimir提供的解决方案和Joe Albahari (c# 4书籍作者)提供的PredicateBuilder。这就是我想出来的。

    public static Expression<Func<TElement, bool>> BuildOrExpression<TElement, TValue>(Expression<Func<TElement, TValue>> valueSelector, IEnumerable<TValue> values)
    {
        if (null == valueSelector) throw new ArgumentNullException("valueSelector");
        if (null == values) throw new ArgumentNullException("values");
        ParameterExpression p = valueSelector.Parameters.Single();
        if (!values.Any()) return e => false;
        Expression<Func<string, string, bool>> expFunc = (name, value) => name.Contains(value);
        IEnumerable<Expression> equals = values.Select(value => (Expression)Expression.Call(valueSelector.Body, typeof(String).GetMethod("Contains"), Expression.Constant(value, typeof(TValue))));
        Expression body = equals.Aggregate<Expression>((accumulate, equal) => Expression.OrElse(accumulate, equal));
        return Expression.Lambda<Func<TElement, bool>>(body, p);
    }
    public static Expression<Func<T, bool>> CombineOr<T>(this Expression<Func<T, bool>> expr1, Expression<Func<T, bool>> expr2)
    {
        var invokedExpr = Expression.Invoke(expr2, expr1.Parameters.Cast<Expression>());
        return Expression.Lambda<Func<T, bool>>(Expression.OrElse(expr1.Body, invokedExpr), expr1.Parameters);
    }
    public static Expression<Func<T, bool>> CombineAnd<T>(this Expression<Func<T, bool>> expr1, Expression<Func<T, bool>> expr2)
    {
        var invokedExpr = Expression.Invoke(expr2, expr1.Parameters.Cast<Expression>());
        return Expression.Lambda<Func<T, bool>>(Expression.AndAlso(expr1.Body, invokedExpr), expr1.Parameters);
    }
    [TestMethod()]
    public void OfferComplexSearchTest()
    {
        using (var lifetime = container.BeginLifetimeScope())
        {
            IOfferRepository offerRepository = lifetime.Resolve<IOfferRepository>();
            List<Offer> offers = new List<Offer>();
            List<Expression<Func<Offer, bool>>> expressions = new List<Expression<Func<Offer, bool>>>();
            Expression<Func<Offer, bool>> finalExp = null;
            string[] orQuery = new string[2] { "director".ToUpper(), "jefe".ToUpper() };
            expressions.Add(LinqTools.BuildOrExpression<Offer, string>(c => c.Description.ToUpper(), orQuery));
            expressions.Add(LinqTools.BuildOrExpression<Offer, string>(c => c.Title.ToUpper(), orQuery));
            expressions.Add(LinqTools.BuildOrExpression<Offer, string>(c => c.Keywords.ToUpper(), orQuery));
            finalExp = expressions.Aggregate<Expression<Func<Offer, bool>>>((accomulate, equal) => LinqTools.CombineOr<Offer>(accomulate, equal));
            offers.AddRange(offerRepository.GetMany(LinqTools.CombineAnd<Offer>(finalExp, (x) => x.Publish)));
            Assert.IsTrue(offers.Count > 0, "Error: No Offers found.");
        }
    }