简体   繁体   English

从多个参数构建 IQueryable (EF4) 查询

[英]Build query for IQueryable (EF4) from multiple parameters

I'm trying to build a single "Or" predicate from a list of predicates in the form List<Expression<Func<T, bool>>>我正在尝试从List<Expression<Func<T, bool>>>形式的谓词列表中构建单个“或”谓词

 public static IQueryable<T> Search<T>(this IQueryable<T> source, List<Expression<Func<T, bool>>> predicates = null)
            where T : EntityObject
        {
            if (predicates == null || predicates.Count == 0)
                return source;
            else if (predicates.Count == 1)
                return source.Where(predicates[0]);
            else
            {
                var row = Expression.Parameter(typeof(T), "row");
                var compoundExpression = predicates[0];

                for (int i = 1; i < predicates.Count; i++)
                {
                    compoundExpression = compoundExpression.Or(predicates[i]);
                }
                return source.Where(compoundExpression);
            }
        }

        static Expression<Func<T, bool>> Or<T>(this Expression<Func<T, bool>> lhs, Expression<Func<T, bool>> rhs)
        {
            var row = Expression.Parameter(typeof(T), "row");
            var body = Expression.Or(
                Expression.Invoke(lhs, row),
                Expression.Invoke(rhs, row));
            return Expression.Lambda<Func<T, bool>>(body, row);
        }

But this is returning every row in my source?但这会返回我的源代码中的每一行吗?

For testing I am looking for c=>c.FullName.Contains("Smith") or c=>c.FullName.Contains("Jones")为了测试,我正在寻找c=>c.FullName.Contains("Smith") or c=>c.FullName.Contains("Jones")

I have tried amending to use PredicateBuilder but again it still returns every row in the source.我尝试修改以使用PredicateBuilder但它仍然返回源中的每一行。

public static IQueryable<T> Search<T>(this IQueryable<T> source, List<Expression<Func<T, bool>>> predicates = null)
            where T : EntityObject
        {
            if (predicates == null || predicates.Count == 0)
                return source;
            else if (predicates.Count == 1)
                return source.Where(predicates[0]);
            else
            {
                var pb = PredicateBuilder.False<T>();
                for (int i = 0; i < predicates.Count; i++)
                {
                    pb = pb.Or(predicates[i]);
                }
                return source.AsExpandable().Where(pb);
            }
        }

Any assistance very gratefully received!非常感谢收到任何帮助!

The end result would be to allow AND's as well as OR's最终结果将是允许 AND 和 OR 的
eg c=>c.FullName.Contains("Dav") AND c=>c.CustomerType == 'Staff'例如 c=>c.FullName.Contains("Dav") AND c=>c.CustomerType == 'Staff'

Try尝试

public static IQueryable<T> Search<T>(this IQueryable<T> source, IEnumerable<Expression<Func<T, bool>>> predicates = null)
        where T : EntityObject
    {
        if (predicates == null || !predicates.Any())
            return source;
        else
        {
             ParameterExpression p = Expression.Parameter(typeof(T), "p");
             Expression<Func<T,Bool>> predicate = 
                        Expression.Lambda<Func<T,Bool>(
                                   predicates.Select(l => ReParameteriser(l.Body, l.Paramaters[0], p)
                                             .Aggregate((b1,b2) => Expression.Or(b1,b2)),
                                   new ParamaterExpression[]{p});
            return source.Where(predicate);
        }
   }

public class ReParameteriser : ExpressionVisitor
{
    ParameterExpression originalParameter; 
    ParameterExpression newParameter;

    private ReParameteriser(){}
    protected ReParameteriser (ParameterExpression originalParameter, ParameterExpression newParameter) 
    {
         this.originalParameter = originalParameter;
         this.new = newParameter;
    }

    public static Expression ReParameterise(Expression expression, ParameterExpression originalParameter, ParameterExpression newParameter)
    {
        return new ReParameteriser(original,newParameter).Visit(expression);
    }

    protected override Expression VisitParameter(ParameterExpression node)
    {
        if (node == originalParameter)
            return newParameter;
        else
            return node;
    }
}

Note: The ExpressionVisitor class is .Net4 so if you want to target an earlier enviroment you will need to write your own.注意:ExpressionVisitor 类是 .Net4,因此如果您想针对较早的环境,则需要编写自己的环境。 The code for this is only a google away, but the usual resource is Matt Warren's blog http://blogs.msdn.com/b/mattwar/archive/2008/11/18/linq-links.aspx这个代码只是一个谷歌,但通常的资源是马特沃伦的博客http://blogs.msdn.com/b/mattwar/archive/2008/11/18/linq-links.aspx

Sometimes the weekend does strange things to code!有时周末会做一些奇怪的事情来编码!

Not sure what I've done differently, but this is working:不确定我做了什么不同的事情,但这是有效的:

public static IQueryable<T> Search<T>(this IQueryable<T> source, List<Expression<Func<T, bool>>> predicates = null)
            where T : EntityObject
        {
            if (predicates == null || predicates.Count == 0)
                return source;
            else if (predicates.Count == 1)
                return source.Where(predicates[0]);
            else
            {
                var query = PredicateBuilder.False<T>();
                foreach (var predicate in predicates)
                {
                    query = query.Or(predicate);
                }

                return source.AsExpandable().Where(query);
            }
        }

PredicateBuilder appears to be a great little bit of code. PredicateBuilder 似乎是一小段代码。

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

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