Как я могу создать дерево выражений, которое запрашивает объект со списком <T>в качестве свойства? - PullRequest
1 голос
/ 20 апреля 2010

Простите мое неуклюжее объяснение, но у меня есть класс, который содержит список:

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.

UPDATE:

Я думаю, что добился определенного прогресса в этом:

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 => user.Department - с обобщениями?

Ответы [ 2 ]

0 голосов
/ 22 апреля 2010

Я нашел несколько удовлетворительное решение, где я могу выполнить запрос с синтаксисом, как показано ниже:

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. Он выполняет свою работу, но если у кого-то есть какие-либо предложения или лучший способ использовать непатентованные средства, чтобы мне не приходилось включать этот статический метод в свой класс User, я очень хочу услышать, что вы хотите сказать.

0 голосов
/ 20 апреля 2010

Звучит так, как вы хотите этот инструментарий ?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...