代码之家  ›  专栏  ›  技术社区  ›  David Robbins

如何生成一个表达式树来查询具有List<T>属性的对象?

  •  1
  • David Robbins  · 技术社区  · 16 年前

    请原谅我笨拙的解释,但我有一个类包含一个列表:

    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(); . 据我所知,我的问题是无法评估 user => user.Deparment == "HR" 如果我要发出一个Expression.Invoke。

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

    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=>用户。部门-有泛型?

    2 回复  |  直到 16 年前
        1
  •  0
  •   Craig Stuntz    16 年前

    听起来你想 this toolkit ?

        2
  •  0
  •   David Robbins    16 年前

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

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

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

    缺点是我在用户类本身中包含了子查询功能。它完成了任务,但如果有人有任何建议或更好的方法来使用泛型,这样我就不必在我的用户类中包含这个静态方法,我很想听听你的意见。