web-dev-qa-db-fra.com

Comment utiliser SQL 'LIKE' avec LINQ to Entities?

J'ai une zone de texte qui permet à un utilisateur de spécifier une chaîne de recherche, y compris des caractères génériques, par exemple:

Joh*
*Johnson
*mit*
*ack*on

Avant d'utiliser LINQ to Entities, j'avais une procédure stockée qui prenait cette chaîne en tant que paramètre et qui:

SELECT * FROM Table WHERE Name LIKE @searchTerm

Et puis je ferais juste un String.Replace ('*', '%') avant de le transmettre.

Maintenant, avec LINQ to Entities, j'essaie d'accomplir la même chose. Je sais qu'il existe un support StartsWith, EndsWith et Contains, mais il ne le prend pas en charge de la manière dont j'ai besoin.

J'ai lu à propos de "SqlMethods.Like" et j'ai essayé ceci:

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

Cependant, je reçois l'exception suivante:

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.

Comment pourrais-je obtenir cette même fonctionnalité en utilisant LINQ to Entities?

28
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

Comment le faire fonctionner de manière transparente:

dans votre modèle EDMX, ajoutez:

    <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>

juste après les sections qui commencent:

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

Ensuite, n'importe où dans votre code, ajoutez cette méthode d'extension:

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

Et voila.

Maintenant vous pouvez faire:

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

ou 

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

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

Eh bien, vos choix sont les suivants:

  • Utilisez Contains. Je sais que ça ne vous plait pas, mais on pourrait probablement le faire fonctionner.
  • Choisissez une fonction dans SqlFunctions . Ils sont tous pris en charge dans L2E.
  • Mappez votre propre fonction
  • +1 à @Yury pour ESQL.
8
Craig Stuntz

Tu peux le faire:

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

car Linq to Entity ne peut pas transformer la méthode Contains() en SQL, mais Linq to SQL peut le faire. J'ai essayé de trouver une méthode permettant de faire un casting, enfin, AsQueryable(), ainsi qu'une version générique AsQueryable<T>(). J'ai découvert que je pouvais le faire en l'utilisant de cette façon dans mon cas, mais je ne sais pas quel qu'en soit l'effet secondaire, il perdra peut-être une fonctionnalité à Entity.

3
Athson

la solution consiste à utiliser SQLFunctions.PatIndex

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

où 'searchstring' est le motif à rechercher 'fieldtoSearch' est le champ à rechercher 

Patindex () prend en charge la recherche à l'aide d'une recherche de modèle de chaîne. La recherche est insensible à la casse.

2
Rama

Vous pouvez faire toutes ces déclarations avec LINQ comme ceci

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

Maintenant, EF prend en charge l'utilisation "LIKE" et vous pouvez utiliser tous les caractères génériques SQL. Regarde ça.

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

EDIT- Je pourrais mélanger la syntaxe. J'utilise habituellement des méthodes d'extension. mais contient travaillera.

0
Mike M.

Nous utilisons Database First et EntityFramework.

Le "Mappez votre propre fonction." Cette approche fonctionne pour nous avec le nuget EntityFramework.CodeFirstStoreFunctions .

1 étape: Créez une fonction dans la base de données comme ceci:

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 étape: Installez le nuget EntityFramework.CodeFirstStoreFunctions

Étape 3: Créez une méthode dans votre code comme ceci (je crée la mienne dans la classe DbContext):

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

4 Étape: Initalize EntityFramework.CodeFirstStoreFunctions.

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

5 étape: Vous pouvez maintenant utiliser cette méthode dans votre requête linq.

0
Magu

Vous n'avez pas besoin d'utiliser le signe de pourcentage lors du filtrage. par exemple;

si je veux vérifier ItemName ne contient pas '-' Je vais le faire comme ça

! Item.ItemName.Contains ("-")

En SQL, il sera converti en NOT LIKE '% -%'

0
Ali Sakhi

Il est facilement atteint par les méthodes suivantes

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

Utilisez les spécifications suivantes pour obtenir des caractères génériques

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