web-dev-qa-db-ja.com

エンティティへのLINQでSQL 'LIKE'を使用する方法

ユーザーがワイルドカードを含む検索文字列を指定できるテキストボックスがあります。次に例を示します。

Joh*
*Johnson
*mit*
*ack*on

LINQ to Entitiesを使用する前に、その文字列をパラメーターとして取り、実行するストアドプロシージャを用意しました。

SELECT * FROM Table WHERE Name LIKE @searchTerm

そして、それを渡す前に、String.Replace( '*'、 '%')を実行します。

LINQ to Entitiesを使用して、同じことを達成しようとしています。 StartsWith、EndsWith、Containsのサポートがあることは知っていますが、必要な方法ではサポートされません。

「SqlMethods.Like」について読んで、これを試してみました:

var people = from t in entities.People
             where SqlMethods.Like(t.Name, searchTerm)
             select new { t.Name };

ただし、次の例外が発生します。

LINQ to Entities does not recognize the method 'Boolean Like(System.String, 
System.String)' method, and this method cannot be translated into a store 
expression.

LINQ to Entitiesを使用してこれと同じ機能を取得するにはどうすればよいですか?

29
esac

http://social.msdn.Microsoft.com/Forums/en-US/adodotnetentityframework/thread/6529a35b-6629-44fb-8ea4-3a44d232d6b9/

var people = entities.People.Where("it.Name LIKE @searchTerm", new ObjectParameter("searchTerm", searchTerm));
34
Yury Tarabanko

シームレスに機能させる方法:

eDMXモデルに、以下を追加します。

    <Function Name="String_Like" ReturnType="Edm.Boolean">
      <Parameter Name="searchingIn" Type="Edm.String" />
      <Parameter Name="lookingFor" Type="Edm.String" />
      <DefiningExpression>
        searchingIn LIKE lookingFor
      </DefiningExpression>
    </Function>

始まるセクションの直後:

<edmx:ConceptualModels> <Schema Namespace="Your.Namespace"...

次に、コードの任意の場所に、この拡張メソッドを追加します。

    //prior to EF 6 [System.Data.Objects.DataClasses.EdmFunction("Your.Namespace", "String_Like")]

    //With EF 6
    [System.Data.Entity.DbFunction("Your.Namespace", "String_Like")]
    public static bool Like(this string input, string pattern)
    {
        /* Turn "off" all regular expression related syntax in
         * the pattern string. */
        pattern = Regex.Escape(pattern);

        /* Replace the SQL LIKE wildcard metacharacters with the
         * equivalent regular expression metacharacters. */
        pattern = pattern.Replace("%", ".*?").Replace("_", ".");

        /* The previous call to Regex.Escape actually turned off
         * too many metacharacters, i.e. those which are recognized by
         * both the regular expression engine and the SQL LIKE
         * statement ([...] and [^...]). Those metacharacters have
         * to be manually unescaped here. */
        pattern = pattern.Replace(@"\[", "[").Replace(@"\]", "]").Replace(@"\^", "^");

        return Regex.IsMatch(input, pattern, RegexOptions.IgnoreCase);
    }

そして、そこにあります。

今あなたはできる:

(from e in Entities
 where e.Name like '%dfghj%'
 select e)

または

string [] test = {"Sydney", "Melbourne", "adelaide", "ryde"};

test.Where(t=> t.Like("%yd%e%")).Dump();
12
mlipman

まあ、あなたの選択肢は:

  • Containsを使用します。私はあなたがそれを好きではないことを知っていますが、それはおそらく動作するように作られる可能性があります。
  • SqlFunctions から関数を選択します。これらはすべてL2Eでサポートされています。
  • 独自の関数をマップ
  • ESQLの場合は@Yuryに+1。
8
Craig Stuntz

あなたはこれを行うことができます:

_using System.Data.Entity;  // EntityFramework.dll v4.3
var queryResult=db.Accounts.AsQueryable().Where(x => x.Name.Contains(queryKey));
_

linq to EntityはメソッドContains()をSQLに変換できませんが、Linq to SQLはこれを実行できるためです。キャストできるメソッドを見つけようとしましたが、ついにAsQueryable()もジェネリックバージョンAsQueryable<T>()になりました。私の場合、この方法でこれを使用してこれを行うことができることがわかりましたが、それによってわからない副作用があれば、Entityで一部の機能が失われる可能性があります。

3
Athson

解決策は SQLFunctions.PatIndex を使用することです

var result = from c in items
             where SqlFunctions.PatIndex(searchstring.ToLower(), c.fieldtoSearch) > 0
             select c;

ここで、 'searchstring'は検索するパターンです 'fieldtoSearch'は検索するフィールドです

Patindex()は、文字列パターン検索を使用した検索をサポートしています。検索では大文字と小文字が区別されません。

2
Ram

あなたはこのようなLINQでこれらすべてのステートメントを行うことができます

string _search = "johnson";
// joh* OR joh%
items.Where(i => i.Name.StartsWith(_search, StringComparison.OrdinalIgnoreCase));
// *son OR %son
items.Where(i => i.Name.EndsWith(_search, StringComparison.OrdinalIgnoreCase));
// *hns* OR %hns%
items.Where(i => i.Name.ToLower().Contains(_search));
1
sairfan

現在、EFは "LIKE"の使用をサポートしており、すべてのSQLワイルドカードを使用できます。これをチェックしてください。

var people = from t in entities.People
             select new { t.Name };
people = people.Where(x => DbFunctions.Like(x.Name, searchTerm));
1
boyukbas
var people = from t in entities.People
                 where t.Name.ToLower().Contains(searchTerm.ToLower())
                 select new { t.Name };

編集-私は構文を混合しているかもしれません。私は通常、拡張メソッドを使用します。が含まれますが動作します。

1
Mike M.

Database FirstとEntityFrameworkを使用します。

「自分の機能をマッピングする」。アプローチは、nuget EntityFramework.CodeFirstStoreFunctions と一緒に機能します。

1ステップ:次のようにデータベースに関数を作成します。

CREATE FUNCTION [dbo].[StringLike]
(
      @a nvarchar(4000),
      @b nvarchar(4000)
)
RETURNS bit
AS
BEGIN
    RETURN 
    (SELECT CASE
            WHEN (SELECT 1 WHERE @a LIKE @b) = 1 THEN 1
            ELSE 0
            END)  
END

2ステップ:nuget EntityFramework.CodeFirstStoreFunctionsをインストールする

3ステップ:次のようにコードでメソッドを作成します(私はDbContextクラスで作成します):

[DbFunction("CodeFirstDatabaseSchema", "StringLike")]
public static bool Like(string input, string pattern)
{
    throw new NotSupportedException("Direct calls are not supported.");
}

4ステップ:EntityFramework.CodeFirstStoreFunctionsを初期化します。

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
    modelBuilder.Conventions.Add(new FunctionsConvention("dbo", this.GetType()));
}

5ステップ:これで、このメソッドをlinqクエリで使用できます。

0
Magu

フィルタリング中にパーセント記号を使用する必要はありません。例えば;

itemNameに「-」が含まれていないことを確認する場合は、次のようにします

!Item.ItemName.Contains( "-")

SQLでは、NOT LIKE '%-%'に変換されます

0
Ali Sakhi

以下の方法で簡単に実現できます

var people = from t in entities.People
             where t.Name.Contains(searchTerm)
             select new { t.Name };

ワイルドカードを実現するには、次の仕様を使用します

LIKE 'a%' => StartsWith("a")
LIKE '%a' => EndsWith("a")
LIKE '%a%' => Contains("a")
LIKE 'a%b' => StartsWith("a") && EndsWith("b")
LIKE '%a%b%' => StartsWith("a") && Contains("b")
0
Shyam Bhagat