[英]Chaining OR conditions in EF 5.0
我將在前面加上我正在積極尋找解決這個問題的方法,但我想如果有人在堆棧上找到這個問題,我可能會縮短一些研究和開發時間。 (我在網上找不到任何東西,所以這里有)
我們在構建的應用程序框架中有一個案例,我們需要能夠接受一組Predicates( List<Expression<Func<T,bool>>>
)並在搜索框架中解析它。
現在我們有能力以這種方式過濾:
//Assume predicates is passed as a method argument.
// of List<Expression<Func<T,bool>>>
//Assume user is passed in as a method argument.
//Assume FilterToUserAccess is a custom extension method that restricts the dataset
// to access restrictions.
var query = _dbContext.Set<EntityType>()
.FilterToUserAccess(user);
foreach(var p in predicates){
query = query.Where(p);
}
return p.ToList();
我們需要這樣做的原因是可過濾對象的可擴展性。 但是,對於快速搜索,鑒於EF的內置功能,這是不可能的。 我需要做的是:
對象A(讓我們假裝它是一輛賽車),我們想在快速搜索框中搜索品牌,型號,團隊和驅動程序。 因此,如果我輸入“Earnhardt”,它將搜索所有賽車實體屬性,包括品牌,型號,團隊和驅動程序。 我最終會得到所有的DEI汽車以及Dale Jr.我想使用相同的方法,因此我們可以配置一個可搜索的實體並在應用程序啟動時反映搜索配置。 理想情況下,我想讓查詢看起來像這樣:
//Assume predicates is passed as a method argument.
// of List<Expression<Func<T,bool>>>
//Assume user is passed in as a method argument.
//Assume FilterToUserAccess is a custom extension method that restricts the dataset
// to access restrictions.
var query = _dbContext.Set<EntityType>()
.FilterToUserAccess(user);
foreach(var p in predicates){
query = query.Or(p);
}
return p.ToList();
我意識到我能做到:
_dbContext.Set<EntityType>().Where(predicate1 || predicate2 || predicate3)
但是,這對我們想要解決此問題的方法不起作用。 理想情況下,我們的一個客戶端站點的管理員可以進入並配置一個額外的搜索詞,只需單擊即可包含在該實體類型的任何和所有快速搜索中,就像我們目前可以使用標准的過濾器一樣.Where(...)
“和”鏈接邏輯。
第一個解決方案是破產,但是通過更多的挖掘,有一個非常簡單的解決方案,經過驗證和工作。
第1步:為LinqKit安裝NuGet包。
第2步:享受下面的代碼
using (ISampleRepository repo = new SampleRepository())
{
var predicates = new List<Expression<Func<Customer,bool>>>(){
(x => x.FirstName.Contains(searchValue)),
(x => x.LastName.Contains(searchValue))
};
var lambda = PredicateBuilder.False<Customer>();
lambda = predicates.Aggregate(lambda, (current, p) => current.Or(p).Expand());
var query = repo.QueryCustomers().AsExpandable().Include(x => x.Phones).Where(lambda);
return query.Take(500)
.ToList()
.Select(x => x.ToDTO())
.ToList();
}
這只是尖峰樣本,但是使用 - >的方法做同樣的事情
List<T> QuickSearch<T>(string input) ...
將能夠使用相同的方法。 您仍然以傳遞的Expression形式存在一組謂詞,然后使用謂詞構建器技巧來關閉查詢。 然后使用AsExpandable()允許您執行使用謂詞構建器創建的組合謂詞。
希望這不僅僅對我有幫助,但這是我要使用的解決方案,因為它的代碼要少得多。 允許您在其他地方構建謂詞...並且在事實之后仍然將它們組合在“OR”語句中。
正如Ladislav所說,您需要動態生成LINQ表達式。 下面是一個動態構建整數集合謂詞的程序的簡單示例:
class Program {
static void Main(string[] args) {
// Retreive your data source
List<int> numbers = new List<int>() { 0, 10, 20, 30, 40, 50, 60 };
// Create a collection of predicates that you would like to chain together.
ParameterExpression parameterExpression = Expression.Parameter(typeof(int), "x");
List<Expression> predicates = new List<Expression>();
// x >= 50
predicates.Add(Expression.GreaterThanOrEqual(parameterExpression, Expression.Constant(50)));
// x <= 20
predicates.Add(Expression.LessThanOrEqual(parameterExpression, Expression.Constant(20)));
// Build a single predicate by chaining individual predicates together in an OR fashion
Expression whereFilter = Expression.Constant(false); // Use false a base expression in OR statements
foreach (var predicate in predicates) {
whereFilter = Expression.OrElse(whereFilter, predicate);
}
// Once the expressions have been chained, create a lambda to represent the whole predicate
// x => (x >= 50) || (x <= 20)
Expression<Func<int, bool>> whereLambda =
(Expression<Func<int, bool>>)Expression.Lambda(whereFilter,
new List<ParameterExpression>() { parameterExpression });
// To use an expression directly, the datasource must be an IQueryable
// Since I am using List<T> I must call AsQueryable. This is not necessary
// if your collection is already IQueryable, like in Entity Framework.
var results = numbers.AsQueryable().Where(whereLambda);
}
}
基本上我在這里做的就是創建幾個布爾值(x> = 50)和(x <= 20)並將它們放在一個集合中。 然后通過循環遍歷該集合,我將每個語句和OR一起轉到最后一個語句。 結果是一系列布爾語句都通過OR鏈接在一起。 然后我將該語句包裝在Lambda表達式中,以便IQueryable.Where
可以使用它並將其傳遞給我的可查詢集合。 結果是我的全套過濾的整數集。
至少可以說LINQ表達式令人困惑,但它們非常強大且值得知道。 如果我能做些什么來幫助我更好地理解這個例子,請告訴我。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.