2017-05-26 16 views
1

這是the tutorial我下面來詳細表達式樹。表達如何寫string.Contains(someText)樹

我已經超過35列顯示,但用戶可以選擇在一次顯示10列。因此,用戶在搜索框中鍵入內容,我只想搜索用戶可見的列。

SELECT FirstName, LastName, Address, ..., State 
FROM Students 
WHERE Id == @Id col1 AND (
     FirstName LIKE '%@searchText%' OR 
     LastName LIKE '%@searchText%' OR 
     Address LIKE '%@searchText%' OR 
     ... 
     State LIKE '%@searchText%') 

返回到LINQ,這就是我正在努力完成它:

​​

這種私有方法:

private Expression<Func<Student, bool>> GetPredicate(int id, List<string> listOfColumns) 
{ 
    ParameterExpression pe = Expression.Parameter(typeof(Student), "s"); 

    Expression left0 = Expression.Property(pe, "Id"); 
    Expression right0 = Expression.Constant(id); 
    Expression e0 = Expression.Equal(left0, right0); 

    //Here ... omitted code because it's not working... 
    // 

    var expr = Expression.Lambda<Func<Student, bool>>(e0, new ParameterExpression[] { pe }); 
     return expr; 
} 

因爲它上面,它的工作就好了。但是,我甚至寫了這個方法的原因是隻能通過用戶選擇的列進行過濾。

我希望能夠基於是在UI中可見柱組成。

if(!string.IsNullOrEmpty(searchText)) 
{ 
    foreach (string columnName in columnList) 
    { 
     Expression col = Expression.Property(pe, columnName); 
     Expression left = Expression.Call(pe, typeof(string).GetMethod("Contains")); 
     Expression right = Expression.Constant(searchText); 
     Expression e = Expression.IsTrue(left, right); 
    } 
} 

我完全失去了。我知道我需要訪問字符串類的Contains方法,然後我不知道接下來會發生什麼。這樣做是爲了得到這樣的:

Where(d => d.Id == id && (d.FirstName.Contains(searchText) 
     || d.LastName.Contains(searchText) 
     || ... 
     || d.State.Contains(searchText))) 

感謝您的幫助

+1

雖然重複問同樣的事情,答案只有是問題的一部分,其上OP相當接近反正提供的信息。另一部分,將多個表達式組合成單個「OR」鏈的部分,不包括對重複問題的所有答案,包括已接受的答案。投票重新提出此問題,以解釋重複中缺失的部分。 – dasblinkenlight

+0

@dasblinkenlight問題的兩個部分(現在是您的答案中的第三個關於嵌套屬性訪問器的註釋)是重複的並且已被回答。我剛剛選擇了與帖子標題相匹配的那個。一般來說,他們應該被問及(因此分開重複:)。 –

回答

1

你是相當接近,除了構建的Contains通話不具有右側:

Expression col = Expression.Property(pe, columnName); 
Expression contains = Expression.Call(
    pe 
, typeof(string).GetMethod("Contains") // Make a static field out of this 
, Expression.Constant(searchText)  // Prepare a shared object before the loop 
); 

一旦你有你的電話表達,與OrElse將它們結合起來,產生的拉姆達的身體。你可以用循環做到這一點,或者你可以使用LINQ:

private static readonly MethodInfo Contains = typeof(string).GetMethod(nameof(string.Contains)); 

public static Expression<Func<Student,bool>> SearchPredicate(IEnumerable<string> properties, string searchText) { 
    var param = Expression.Parameter(typeof(Student)); 
    var search = Expression.Constant(searchText); 
    var components = properties 
     .Select(propName => Expression.Call(Expression.Property(param, propName), Contains, search)) 
     .Cast<Expression>() 
     .ToList(); 
    // This is the part that you were missing 
    var body = components 
     .Skip(1) 
     .Aggregate(components[0], Expression.OrElse); 
    return Expression.Lambda<Func<Student, bool>>(body, param); 
} 
+0

它像魅力一樣工作。我甚至可以使用'Expression.AndAlso()'將's.Id == id'條件與您提供的條件相結合。如果我感興趣的財產也是另一物業的財產?讓我們通過導航屬性:'p => p.Category.CategoryId == categoryId'。 – Richard77

+0

@ Richard77當你需要屬性的屬性時,構造'Expression.Property(Expression.Property(param,「Category」),「CategoryId」)'。你也可以在一個循環中完成它 - 在''。''上分割''Category.CategoryId「',然後繼續在部件上調用'Expression.Property',使用前面的表達式作爲第一個參數。 – dasblinkenlight

+0

非常感謝。我在這方面學到了很多東西。 – Richard77

0

我喜歡這樣的場景在PredicateBuilder類的東西:

using System; 
using System.Linq; 
using System.Linq.Expressions; 
using System.Collections.Generic; 

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

使用這種看起來像代碼:

var predicate = PredicateBuilder.True<Student>().And(i=>i.Id==id); 
if(!string.IsNullOrEmpty(searchText)) 
{ 
    if (firstNameColumnVisible) { 
     predicate = predicate.And(i=>i.FirstName.Contains(searchText)); 
    } 
    if (lastNameColumnVisible) { 
     predicate = predicate.And(i=>i.LastName.Contains(searchText)); 
    } 
    // more columns here. 
} 

最後,使用PredicateBuilder實例作爲參數傳遞給你的Linq查詢中的運算符。

+0

那麼沒有辦法循環訪問columnName列表? – Richard77