开发者

How can I generate an Expression tree that queries an object with List<T> as a property?

Forgive my clumsy explanation, but I have a class that contains a List:

public class Document
    {
        public int OwnerId { get; set; }
        public List<User> Users { get; set; }

        public Document() { }
    }

    public class User
    {
        public string UserName { get; set; }
        public string Department { get; set; }
    }

Currently I use PredicateBuilder to perform dynamic queries on my objects. How can I turn the following LINQ statement into an Expression Tree:

var predicate= PredicateBuilder.True<User>();
predicate= predicate.And<User>(user => user.Deparment == "HR"); 

var deptDocs = documents.AsQueryable()
          .Where(doc => doc.Users
          .AsQueryable().Count(predicate) > 0)
          .ToList();

In other words var deptDocs = documents.HasUserAttributes("Department", "HR").ToList();. From what I can tell, my issue is not being able to evaluate the user => user.Deparment == "HR" row by row if I were to issue an Expression.Invoke.

UPDATE:

I think I have made some progress on this:

var predicate = PredicateBuilder.True<User>();
predicate = predicate.And<User>(user => user.Department == "FIN");

Expression<Func<Document, bool>> userSelector =
            doc => doc.Users
            .AsQueryable()
            .Any(predicate);

var docParm = Expression.Parameter(typeof(Document), "appDoc");
var body = Expression.Invoke(userSelector, docParm);
var lambda = Expression.Lambda<Func<Document, bool>>(body, docParm);

var allPredicate = PredicateBuilder.True<Document>();            
allPredicate = allPredicate.And<Document>(doc => doc.OwnerId == 1);
allPredicate = allPredicate.And<Document>(lambda);

var hrDocs = this.docs.AsQueryable().Where(allPredicate).ToList();

Is there a more effective way to do this? How can I make an expre开发者_如何学Gossion that creates the predicate - user => user.Department - with generics?


Sounds like you want this toolkit?


I've come up with a somewhat satisfactory solution where I can perform the query with syntax like below:

var predicate = PredicateBuilder.True<Document>();
predicate = predicate.And<Document>(User.SubQuery("UserName", "DAVER"));
predicate = predicate.And<Document>(AdHoc<Document>("OwnerId", 1));

var finDocs = docs.AsQueryable().Where(predicate).ToList();

I have an extension class with this method:

public static Expression<Func<T, bool>> AdHoc<T>
            (string columnName, object compValue)
{
    //  Determine type of parameter
    ParameterExpression parameter = Expression.Parameter(typeof(T), "x");
    //  Target to compare to
    Expression property = Expression.Property(parameter, columnName);
    //  The value to match
    Expression constant = Expression.Constant(compValue, compValue.GetType());

    Expression equality = Expression.Equal(property, constant);
    Expression<Func<T, bool>> predicate =
    Expression.Lambda<Func<T, bool>>(equality, parameter);

    return predicate;
}

And on my User class I have a static method:

public static Expression<Func<Document, bool>> SubQuery(string property, 
                                                         string targetValue)
        {
            var predicate = PredicateBuilder.True<User>();
            predicate = predicate.And<User>(Extensions.AdHoc<User>(property, targetValue));

            Expression<Func<Document, bool>> userSelector =
                                    doc => doc.Users
                                        .AsQueryable()
                                        .Any(predicate);

            var docParm = Expression.Parameter(typeof(Document), "appDoc");
            var body = Expression.Invoke(userSelector, docParm);

            var docPredicate = PredicateBuilder.True<Document>();
            docPredicate = docPredicate.And<Document>(Expression.Lambda<Func<Document, bool>>(body, docParm));

            return docPredicate;
        }

The drawback is that I've included the Subquery functionality on the User class itself. It gets the job done, but if anyone has any suggestions or a better way to use generics so I don't have to include this static method on my User class I'm eager to hear what you have to say.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜