简体   繁体   English

String.Contains和string []的表达式构建器函数

[英]Expression builder function for String.Contains and string[]

I'm having a hard time creating an expression builder function to pass to a query for NHibernate repository. 我很难创建表达式构建器函数来传递给NHibernate存储库的查询。

Basically what I want to be able to do is build a query from various object properties (strings) and compare their value to values in an array. 基本上我想要做的是从各种对象属性(字符串)构建一个查询,并将它们的值与数组中的值进行比较。 Also be able to add other query sentences. 也可以添加其他查询语句。

Something like 就像是

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

But instead of doing the Expression.Equal somehow doing a String.Contains . 但是,而不是做Expression.Equal莫名其妙地做了String.Contains

Any help welcomed. 欢迎任何帮助。 By the way the code above is not tested. 顺便说一句,上面的代码没有经过测试。

Instead of Expression.Equal you need to use Expression.Call and pass Contains MethodInfo instance. 而不是Expression.Equal您需要使用Expression.Call并传递Contains MethodInfo实例。 Something like this 像这样的东西

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

I was able to overcome the expression combining problem but Im not sure this is the best solution. 我能够克服结合问题的表达,但我不确定这是最好的解决方案。 Any who I used the solution provided by Vladimir and PredicateBuilder by Joe Albahari (C# 4 book writer). 任何我使用弗拉基米尔和PredicateBuilder由Joe Albahari(C#4书作家)提供的解决方案的人。 This is what I came up with. 这就是我提出的。

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM