2011-02-02 14 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ではないL2Eを使用しているので、私は他の解決策が必要です。

+0

今の私は、動的SQL文字列を作成し、ExecuteStoreQuery を通してそれを実行し、私の問題を解決します。 – WhoIsNinja

答えて

2

this articleを試すことができます。ここでは、LINQ to Entitiesにワイルドカード文字を含むLIKE文を作成する方法について説明します。

EDIT:元のリンクが死んでいるので、元の拡張クラス(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

+0

ここに例があります:entities.Table.WhereLike(el => el.position、position、 '%')。したがって、検索する列とワイルドカード文字を検索する列を設定する必要があります。しかし、私はそれをテストし、それがあなたを助けないことを発見しました - それは、パターンの開始または終了ではないワイルドカードを処理しません、申し訳ありません。 – EvgK

+2

しかし、どのように複数のWhere節を結合しますか?たとえば、 "WHERE FirstName LIKE 'A%'またはLastName LIKE 'A%'"を生成するには? – parleer

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

これは必須ではありません。すべてのファイルを取得していて、これをフィルタリングすることは、不要なデータ転送です。 – WhoIsNinja

+0

代替手段はありますか?私はちょうど私のコードで、私はどのように選択し、同時にファイル名をクエリすることができますか? – Ziv

+0

代わりにDirectory.EnumerateFiles(path、searchPattern)を使用してください。 (しかし、私は彼がDBを照会したいと思うと思う) – Magnus

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

は、ここで私は私のプロジェクトでは、必要に応じて、再利用可能な拡張メソッドです。

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の拡張機能を使用したい場合は、これから始めることができます。

+0

おかげ@Legolomaniacは、 は、これは本当に素晴らしい解決策ですが、私は特に ' ソース= source.And( ' それは私に語った、上...それは構築するのに問題を抱えています「いいえメソッドのオーバーロード 『と』 1つの引数を取ります」** – m1m1k

15

SQLメソッドPATINDEXは、LIKEと同じ機能を提供します。そのため、あなたはSqlFunctions.PatIndexメソッドを使用することができます。

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

は魅力のように働いたおかげBG –

+0

注意:あなたは「System.Data.Entity.SqlServerを使用して、」必要はありません「System.Data.Objects.SqlClientを使用して、。! "参照してくださいhttp://stackoverflow.com/questions/19733085/linq-to-entities-does-not-recognize-the-method-system-string-stringconverttsyst – jgerman

+0

優秀!はい、' LIKE == PATINDEX> 0' https: //docs.microsoft.com/en-us/sql/t-sql/functions/patindex-transact-sql人々は本当にupvoする必要がありますほとんどすべての投稿には(この投稿のように)間違った答えがたくさんあるので、この答えをしてください。これを行う方法は実際には難しいです。 – briantyler

0

をだから私は同じことをしようとしていた - 検索語にマッチしたすべての候補を返すためにリストを下にペアリングしようとしています。ユーザーが「アリゾナ」と入力した場合、アリゾナ州の事件に関係なくすべてを返すようにしたいと思っていました。また、ユーザーが「Arizona Cha」と入力すると、「Arizona License 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; 
    } 
関連する問題