在许多 AND 之间构建一个具有嵌套 OR 的动态表达式
Build a dynamic expression with nested OR between many ANDS
我正在尝试动态构建如下所示的表达式。
SomeList.Where(person => person.firstname == "foo" &&
(person.lastanme == "bar" ||person.middleName == "bar") &&
person.age == 65)
我正在使用一个名为 PredicateBuilder 的 class :
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 = "";
}
}
}
要创建更复杂的表达式,您可以在 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);
}
}
更新: 或更简洁的示例:
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);
}
}
我正在尝试动态构建如下所示的表达式。
SomeList.Where(person => person.firstname == "foo" &&
(person.lastanme == "bar" ||person.middleName == "bar") &&
person.age == 65)
我正在使用一个名为 PredicateBuilder 的 class :
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 = "";
}
}
}
要创建更复杂的表达式,您可以在 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);
}
}
更新: 或更简洁的示例:
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);
}
}