2017-02-08 16 views
1

Я пытаюсь построить выражение, подобное динамически.Создайте динамическое выражение с вложенным OR между многими ANDS

SomeList.Where(person => person.firstname == "foo" && 
       (person.lastanme == "bar" ||person.middleName == "bar") && 
       person.age == 65) 

Я использую класс под названием PredicateBuilder:

public static class PredicateBuilder 
{ 
    public static Expression<Func<T, bool>> True<T>() { return f => true; } 
    public static Expression<Func<T, bool>> False<T>() { return f => false; } 

    public static Expression<Func<T, bool>> Or<T> (this Expression<Func<T, bool>> expr1, 
                 Expression<Func<T, bool>> expr2) 
    { 
    var invokedExpr = Expression.Invoke (expr2, expr1.Parameters.Cast<Expression>()); 
    return Expression.Lambda<Func<T, bool>> 
      (Expression.OrElse (expr1.Body, invokedExpr), expr1.Parameters); 
    } 

    public static Expression<Func<T, bool>> And<T> (this Expression<Func<T, bool>> expr1, 
                 Expression<Func<T, bool>> expr2) 
    { 
    var invokedExpr = Expression.Invoke (expr2, expr1.Parameters.Cast<Expression>()); 
    return Expression.Lambda<Func<T, bool>> 
      (Expression.AndAlso (expr1.Body, invokedExpr), expr1.Parameters); 
    } 
} 

Я сначала проверить, если свойства объекта поиска заполняются, если они тогда я называю метод, который строит предикат, основанный на это свойство. Затем я добавляю все это в список предикатов. В конце я просматриваю и добавляю все предикаты вместе в списке с помощью метода PredicateBuilder.And().

Однако мне нужно иметь возможность отфильтровывать два разных свойства, например, от имени или от среднего имени.

Я хотел бы привести пример того, как динамически создавать эти предикаты и вставлять их или между ними, когда это необходимо, или предложение для лучшего общего дизайна для удовлетворения моих потребностей.

В приведенном ниже коде я вызываю CreatePredicate().

private static List<Expression<Func<DirectoryEntry,bool>>> _conditionsList = new List<Expression<Func<DirectoryEntry,bool>>>(); 
    public static Expression<Func<DirectoryEntry, bool>> CreatePredicate(DirectorySearchData searchData) 
    { 
     _conditionsList.Clear(); 

     var predicate = PredicateBuilder.False<DirectoryEntry>(); 

     AddFirstNameCondition(searchData); 
     AddLastNameCondition(searchData); 
     AddUsernameCondition(searchData); 

     predicate = BuilPredicateFromConditionList(predicate); 

     return predicate; 
    } 

private static void AddFirstNameCondition(DirectorySearchData searchData) 
    { 
     if (!String.IsNullOrWhiteSpace(searchData.FirstName)) 
     { 
      _conditionsList.Add(entry => entry.FirstName.ToLower().Contains(searchData.FirstName.ToLower())); 
     } 
    } 

    private static void AddLastNameCondition(DirectorySearchData searchData) 
    { 
     if (!String.IsNullOrWhiteSpace(searchData.LastName)) 
     { 
      _conditionsList.Add(entry => entry.LastName.ToLower().Contains(searchData.LastName.ToLower())); 
     } 
    } 

    private static void AddUsernameCondition(DirectorySearchData searchData) 
    { 
     if (!String.IsNullOrWhiteSpace(searchData.UserName)) 
     { 
      _conditionsList.Add(entry => entry.Username.ToLower().Contains(searchData.UserName.ToLower())); 
     } 
    } 

private static Expression<Func<DirectoryEntry, bool>> BuilPredicateFromConditionList(Expression<Func<DirectoryEntry, bool>> predicate) 
    { 
     if (_conditionsList == null || _conditionsList.Count <= 0) return predicate; 

     predicate = PredicateBuilder.True<DirectoryEntry>(); 
     foreach (var condition in _conditionsList) 
     { 
      predicate = PredicateBuilder.And(predicate, condition); 
     } 
     return predicate; 
    } 

    public class DirectorySearchData 
{ 

    public string LastName { get; set; } 
    public string FirstName { get; set; } 
    public string UserName { get; set; } 
    public string CampusPhone { get; set; } 
    public string CampusAddress { get; set; } 
    public string CampusBox { get; set; } 
    public string HomeAddress { get; set; } 
    public string HomeState { get; set; } 
    public string DepartmentOrOffice { get; set; } 
    public string StudentMajor { get; set; } 
    public string Concentration { get; set; } 
    public string SgaCabinetPositionName { get; set; } 
    public string Hiatus { get; set; } 
    public string StudentClass { get; set; } 

    public DirectorySearchData() 
    { 
     LastName = ""; 
     FirstName = ""; 
     UserName = ""; 
     CampusPhone = ""; 
     CampusAddress = ""; 
     CampusBox = ""; 
     HomeAddress = ""; 
     HomeState = ""; 
     DepartmentOrOffice = ""; 
     StudentMajor = ""; 
     Concentration = ""; 
     SgaCabinetPositionName = ""; 
     Hiatus = ""; 
     StudentClass = ""; 
    } 
} 

}

+0

'person.firstname = "Foo" или' person.firstname = = "foo" '? Сначала исправьте свой статический код перед построением динамических выражений;) – grek40

+0

HAHA спасибо, я просто набрал слишком быстро :) – Mike

+0

Обратите внимание, что => это лямбда-оператор! Ваш «пример» содержит четыре (и, следовательно, не имеет смысла), но необходим только один: (p => (pa || pb) && pc) – user1890202

ответ

0

Для создания более выражения сложности вы можете использовать более выражения сложности в Add*Condition методов. Для сборки OR выражения в вашем случае вы можете использовать следующий метод:

private static void AddLastNameOrMiddleNameCondition(DirectorySearchData searchData) 
{ 
    if (!string.IsNullOrWhiteSpace(searchData.LastName)) 
    { 
    var lastNameOrMiddleName = PredicateBuilder.Or(
     (DirectorySearchData entry) => entry.LastName.ToLower().Contains(searchData.LastName.ToLower()), 
     (DirectorySearchData entry) => entry.MiddleName.ToLower().Contains(searchData.MiddleName.ToLower())); 

    _conditionsList.Add(lastNameOrMiddleName); 
    } 
} 

UPD: или более сleaner пример:

private static void AddLastNameOrMiddleNameCondition(DirectorySearchData searchData) 
{ 
    if (!string.IsNullOrWhiteSpace(searchData.LastName)) 
    { 
    var inner = PredicateBuilder.New<DirectorySearchData>(false); 
    // BTW, Use New<T> insted of PredicateBuilder.False<DirectorySearchData>(); methods False<T> and True<T> are obsolete. 
    inner = inner.Or(entry => entry.LastName.ToLower().Contains(searchData.LastName.ToLower())); 
    inner = inner.Or(entry => entry.MiddleName.ToLower().Contains(searchData.MiddleName.ToLower())); 

    _conditionsList.Add(inner); 
    } 
} 
+0

Является ли класс PredicateBuilder вашим обращением к тому же, что и упомянутый выше, или это из другого источника? – Mike

+0

@Mike, Из вашего источника, я использую версию LinqKik 1.1.8.0. Версии менее 1.1.7.1 не включены 'New' и' New 'методы, в этих версиях просто используйте' PredicateBuilder.False () '. –

+1

Большое спасибо, ваш ответ помог мне разобраться в том, чего мне не хватало! Я, очевидно, новичок в создании лямбда-выражений, поэтому я очень ценю ваше время и помощь! – Mike