0

我寫了一個擴展System.Linq類的方法。我的ContainsAnyWord方法允許我搜索字符串中的所有單詞而不是將一個字符串與另一個字符串進行比較。如何讓實體的Linq擴展方法可用?

下面是我寫的延長Linq

public static class LinqExtension 
{ 

    public static bool ContainsAnyWord(this string value, string searchFor) 
    { 
     if (!string.IsNullOrWhiteSpace(value) && !string.IsNullOrWhiteSpace(searchFor)) 
     { 
      value = value.ToLower(); 

      IEnumerable<string> tags = StopwordTool.GetPossibleTags(searchFor); 

      return tags.Contains(value); 

     } 

     return false; 

    } 

} 

這個擴展方法的IEnumerable對象上的偉大工程的方法。但是,當我想用​​它IQueryable對象,我得到以下錯誤

LINQ到實體無法識別方法「布爾 ContainsAnyWord(System.String,System.String)」的方法,而這種方法 不能被翻譯成商店表達。

下面的例子很好,因爲我正在處理一個列表。

using(var conn = new AppContext()) 
{ 

    var allUsers = conn.Users.GetAll().ToList(); 
    var foundUsers = allUsers.Where 
    (
     user => 
       user.FirstName.ContainsAnyWord("Some Full Name Goes Here") 
      || user.LastName.ContainsAnyWord("Some Full Name Goes Here") 
    ).ToList(); 

} 

而是因爲我與IQueryable這給了我上面列出的錯誤工作下面的例子不工作。

using(var conn = new AppContext()) 
{ 

    var allUsers = conn.Users.Where 
    (
     user => 
      user.FirstName.ContainsAnyWord("Some Full Name Goes Here") 
     || user.LastName.ContainsAnyWord("Some Full Name Goes Here") 
    ).ToList(); 

} 

我怎麼能解決這個問題,並提供一些IQueryable對象這種方法嗎?

修訂

基於我在下面得到了反饋,我試圖實現使用IQueryable這個像這樣

public static IQueryable<T> ContainsAnyWord<T>(this IQueryable<T> query, string searchFor) 
    { 
     if (!string.IsNullOrWhiteSpace(searchFor)) 
     { 
      IEnumerable<string> tags = StopwordTool.GetPossibleTags(searchFor); 

      return query.Where(item => tags.Contains(item)); 

     } 

     return query; 

    } 

但是這也給了我一個錯誤

enter image description here

+2

您延長'字符串',而不是'IQueryable '。 –

+0

[這可能是interessting](http://stackoverflow.com/a/24524745/2441442) –

+0

@ChristianGollhardt實現IQueryable不會在Where()中工作。我需要我的代碼在那裏工作,因爲我希望能夠應用一些'OR'運算符邏輯 –

回答

4

你必須記住,這必須翻譯d到SQL。 顯然ContainsAnyWord不能轉換爲SQL ...
所以,保存你的名字在一個列表/陣列,並嘗試

user => yourlist.Contains( user.FirstName) 

WHERE ..IN

沒有必要EF會翻譯這一個一種方法,但如果由於某種原因,你想它

internal static class MyClass2 
{ 
    public static IQueryable<T> ContainsAnyWord<T>(this IQueryable<T> value, string searchFor) where T: User 
    { 
     var names = searchFor.Split(' ').ToList(); 
     return value.Where(u => names.Contains(u.DisplayName)); 
    } 
} 

您可以使用它像

var result=conn.Users.ContainsAnyWord("abc def ght"); 
+0

好點。我的方法的第一個參數看起來像在這種情況下?或者我將如何讓我的擴展方法接受像user.FirstName(或什麼我使用的屬性) –

+0

@MikeA檢查我更新的答案。正如我說的, t需要一個方法... –

+0

@MikeA,但如果你需要更多的一般檢查斯科特張伯倫的回答 –

0

Linq to Entities將Methods轉換爲數據庫表達式。您無法實現對System.String的擴展,並期望將其轉換爲T-SQL表達式,這是內部實體框架的作用。

我的建議是努力解決使用預定義的Linq方法。嘗試使用Contains方法。

1

您不能調用查詢表達式中的方法Linq提供的表達式解析器對於Entite不知道如何處理。你唯一能做的就是編寫一個擴展方法,它接受IQueryable<T>並在函數內部建立表達式,而不是調用Where(

這下面的代碼是完全未經測試的,並且是我從上面得到的東西我的頭。但是,你需要做這樣的事情

public static IQueryable<T> WhereContainsAnyWord<T>(this IQueryable<T> @this, Expression<Func<T, string>> selector, string searchFor) 
{ 
    var tags = StopwordTool.GetPossibleTags(searchFor); //You might need a .ToArray() here. 

    var selectedItems = @this.GroupBy(selector); 
    var filteredItems = selectedItems.Where(selectedItem => tags.Contains(selectedItem.Key.ToLower())); 
    var result = filteredItems.SelectMany(x => x); 
    return result; 
} 
使用像

using(var conn = new AppContext()) 
{ 

    var allUsers = conn.Users.WhereContainsAnyWord(user => user.FirstName, "Some Full Name Goes Here").ToList(); 

} 

這裏是一個simpiler非通用版本

public static IQueryable<User> WhereContainsAnyWord(this IQueryable<User> @this, string searchFor) 
{ 
    var tags = StopwordTool.GetPossibleTags(searchFor); //You might need a .ToArray() here. 

    return @this.Where(user => tags.Contains(user.DisplayName.ToLower())); 
} 

使用像

using(var conn = new AppContext()) 
{ 

    var allUsers = conn.Users.WhereContainsAnyWord("Some Full Name Goes Here").ToList(); 

} 
+0

簡單的'@'在這裏做什麼?另外,你爲什麼要做'GroupBy' –

+0

@讓你使用單詞'this'作爲變量名,因爲'this'是一個保留字。在擴展方法中調用第一個參數'@ this'是我前段時間從某處獲得的習慣。 'GroupBy' /'.SelectMany'對是一個黑客,所以我可以根據傳入的'selector'進行過濾,但是得到的結果是函數返回仍然是'T'而不是'selector'的輸出。如果我有更多時間,我會寫[自定義'Expression'](https://msdn.microsoft.com/en-us/library/system.linq.expressions.expression(v = vs.110).aspx)返回一個annonamous類型,但GroupBy更快。 –

+0

這項工作很好。但是,我將如何使用它來檢查多個屬性?例如'FirstName =「Something」|| LastName =「Something」'注意到我可以做到這一點的方法。 –