如何生成一个表达式树,以List <t>作为属性查询对象?</t>

时间:2010-04-20 17:39:51

标签: c# linq-to-objects expression-trees

原谅我笨拙的解释,但我有一个包含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; }
    }

目前我使用PredicateBuilder对我的对象执行动态查询。如何将以下LINQ语句转换为表达式树:

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

换句话说var deptDocs = documents.HasUserAttributes("Department", "HR").ToList();。据我所知,如果我要发出Expression.Invoke,我的问题是无法逐行评估user => user.Deparment == "HR"

更新

我想我在这方面取得了一些进展:

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

有更有效的方法吗?如何创建一个创建谓词的表达式 - user =&gt; user.Department - 有泛型吗?

2 个答案:

答案 0 :(得分:0)

听起来像你想要this toolkit

答案 1 :(得分:0)

我提出了一个令人满意的解决方案,我可以使用如下语法执行查询:

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

我有一个使用此方法的扩展类:

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

在我的User类中,我有一个静态方法:

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

缺点是我在User类本身中包含了Subquery功能。它完成了工作,但如果有人有任何建议或更好的方式来使用泛型,所以我不必在我的用户类上包含这个静态方法,我很想知道你要说的话。