2011-02-02 44 views
8

我正在使用LINQ 2實體。 以下是問題:像運算符或在LINQ to Entities中使用通配符

string str = '%test%.doc%' 
.Contains(str) // converts this into LIKE '%~%test~%.doc~%%' 

的預期轉換:LIKE '%測試%的.doc%'

如果是LINQ 2 SQL,我可以用SqlMethods.Like正如有人在我之前的回答了這個問題題。但現在,因爲我使用的是L2E而不是L2S,所以我需要其他解決方案。

+0

現在我創建了一個SQL字符串動態,並通過ExecuteStoreQuery 執行它解決了我的問題。 – WhoIsNinja 2011-02-03 23:08:31

回答

2

您可以嘗試使用this article,其中作者描述如何在LINQ to Entities中使用通配符構建LIKE語句。

編輯:由於原來的鏈接現在已經死了,這裏是原來的擴展類(根據Jon Koeter in the comments)和使用示例。

擴展:

public static class LinqHelper 
{ 
    //Support IQueryable (Linq to Entities) 
    public static IQueryable<TSource> WhereLike<TSource>(this IQueryable<TSource> source, Expression<Func<TSource, string>> valueSelector, string value, char wildcard) 
    { 
     return source.Where(BuildLikeExpression(valueSelector, value, wildcard)); 
    } 

    //Support IEnumerable (Linq to objects) 
    public static IEnumerable<TSource> WhereLike<TSource>(this IEnumerable<TSource> sequence, Func<TSource, string> expression, string value, char wildcard) 
    { 
     var regEx = WildcardToRegex(value, wildcard); 

     //Prevent multiple enumeration: 
     var arraySequence = sequence as TSource[] ?? sequence.ToArray(); 

     try 
     { 
      return arraySequence.Where(item => Regex.IsMatch(expression(item), regEx)); 
     } 
     catch (ArgumentNullException) 
     { 
      return arraySequence; 
     } 
    } 

    //Used for the IEnumerable support 
    private static string WildcardToRegex(string value, char wildcard) 
    { 
     return "(?i:^" + Regex.Escape(value).Replace("\\" + wildcard, "." + wildcard) + "$)"; 
    } 

    //Used for the IQueryable support 
    private static Expression<Func<TElement, bool>> BuildLikeExpression<TElement>(Expression<Func<TElement, string>> valueSelector, string value, char wildcard) 
    { 
     if (valueSelector == null) throw new ArgumentNullException("valueSelector"); 

     var method = GetLikeMethod(value, wildcard); 

     value = value.Trim(wildcard); 
     var body = Expression.Call(valueSelector.Body, method, Expression.Constant(value)); 

     var parameter = valueSelector.Parameters.Single(); 
     return Expression.Lambda<Func<TElement, bool>>(body, parameter); 
    } 

    private static MethodInfo GetLikeMethod(string value, char wildcard) 
    { 
     var methodName = "Equals"; 

     var textLength = value.Length; 
     value = value.TrimEnd(wildcard); 
     if (textLength > value.Length) 
     { 
      methodName = "StartsWith"; 
      textLength = value.Length; 
     } 

     value = value.TrimStart(wildcard); 
     if (textLength > value.Length) 
     { 
      methodName = (methodName == "StartsWith") ? "Contains" : "EndsWith"; 
     } 

     var stringType = typeof(string); 
     return stringType.GetMethod(methodName, new[] { stringType }); 
    } 
} 

用法示例:

string strEmailToFind = "%@yahoo.com" 

IQueryable<User> myUsers = entities.Users.WhereLike(u => u.EmailAddress, strEmailToFind, '%'); 

,或者,如果你希望你的用戶更習慣於Windows資源管理器風格的通配符:

string strEmailToFind = "*@yahoo.com" 

IQueryable<User> myUsers = entities.Users.WhereLike(u => u.EmailAddress, strEmailToFind, '*'); 
+0

我剛纔看到,它沒有使用它的例子 – WhoIsNinja 2011-02-02 19:52:15

+0

下面是一個例子:entities.Table.WhereLike(el => el.position,position,'%')。所以你應該設置你正在搜索的列,模式搜索和通配符。但是我已經測試了它,發現它不會幫助你 - 它不處理那些不在模式開始或結束的通配符,對不起。 – EvgK 2011-02-02 21:02:34

+2

但是,如何結合多個Where子句?例如,要生成「WHERE FirstName LIKE'A%'或LastName LIKE'A%'」? – parleer 2012-01-09 21:50:34

2

使用正則表達式...

下面將打印出所有的文件中匹配測試 .DOC *當前目錄(DOS通配符的風格 - 我相信這是你問的)

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 
using System.Text.RegularExpressions; 
using System.IO; 

namespace RegexFileTester 
{ 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      string[] _files = Directory.GetFiles("."); 
      var _fileMatches = from i in _files 
           where Regex.IsMatch(i, ".*test*.doc.*") 
           //where Regex.IsMatch(i, ".*cs") 
           select i; 
      foreach(var _file in _fileMatches) 
      { 
       Console.WriteLine(_file); 
      } 
     } 
    } 
} 
2

分割字符串

var str = "%test%.doc%"; 
var arr = str.Split(new[]{'%'} ,StringSplitOptions.RemoveEmptyEntries); 
var q = tblUsers.Select (u => u); 
foreach (var item in arr) 
{ 
    var localItem = item; 
    q = q.Where (x => x.userName.Contains(localItem)); 
} 
3

從Magnus的正確答案繼,這裏是一個擴展方法,其可重複使用,因爲我需要在我的項目。

public static class LinqExtensions 
{ 
    public static Expression<Func<T, bool>> WildCardWhere<T>(this Expression<Func<T, bool>> source, Expression<Func<T, string>> selector, string terms, char separator) 
    { 
     if (terms == null || selector == null) 
      return source; 

     foreach (string term in terms.Split(new[] { separator }, StringSplitOptions.RemoveEmptyEntries)) 
     { 
      string current = term; 
      source = source.And(
       Expression.Lambda<Func<T, bool>>(
        Expression.Call(selector.Body, "Contains", null, Expression.Constant(current)), 
        selector.Parameters[0] 
       ) 
      ); 
     } 

     return source; 
    } 
} 

用法:

var terms = "%test%.doc%"; 
Expression<Func<Doc, bool>> whereClause = d => d; 
whereClause = whereClause.WildCardWhere(d => d.docName, terms, '%'); 
whereClause = whereClause.WildCardWhere(d => d.someOtherProperty, "another%string%of%terms", '%'); 
var result = ListOfDocs.Where(whereClause).ToList(); 

的擴展使用謂詞建設者在http://petemontgomery.wordpress.com/2011/02/10/a-universal-predicatebuilder/。結果sql執行表的單個表掃描,無論有多少條款。 Jo Vdb有一個example,如果你想要擴展iQueryable,你可以從這裏開始。

15

SQL方法PATINDEX提供了與LIKE相同的功能。因此,你可以使用SqlFunctions.PatIndex方法:

.Where(x => SqlFunctions.PatIndex("%test%.doc%", x.MySearchField) > 0) 
0

所以我嘗試同樣的事情 - 嘗試配對下來列表返回匹配一個SEARCHTERM所有候選人。我希望如此,如果用戶輸入「亞利桑那」,它將返回一切,無論亞利桑那州的情況如何。此外,如果用戶輸入「Arizona Cha」,它將返回「Arizona Licence Change」等項目。以下工作:

private List<Certification> GetCertListBySearchString() 
    { 
     string[] searchTerms = SearchString.Split(' '); 
     List<Certification> allCerts = _context.Certifications.ToList(); 

     allCerts = searchTerms.Aggregate(allCerts, (current, thisSearchString) => (from ac in current 
                        where ac.Name.ToUpper().Contains(thisSearchString.ToUpper()) 
                        select ac).ToList()); 
      return allCerts; 
    }