2010-06-22 12 views
25

tengo un cuadro de texto que permite a un usuario especificar una cadena de búsqueda, incluyendo comodines, por ejemplo:¿Cómo se usa SQL 'LIKE' con LINQ para Entidades?

Joh* 
*Johnson 
*mit* 
*ack*on 

Antes de utilizar LINQ a Entidades, que tenía un procedimiento almacenado que se llevó a esa cadena como parámetro y lo hizo:

SELECT * FROM Table WHERE Name LIKE @searchTerm 

Y entonces yo sólo haría un String.Replace ('*', '%') antes de pasarlo en.

Ahora con LINQ a Entidades que estoy tratando de lograr lo mismo. Sé que hay compatibilidad con StartsWith, EndsWith y Contiene, pero no la admitirá de la manera que necesito.

leí sobre "SqlMethods.Like" y probamos este:

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

Sin embargo estoy recibiendo la siguiente excepción:

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. 

¿Cómo voy a conseguir esta misma funcionalidad utilizando LINQ a Entidades?

Respuesta

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

EDIT- I might be mixing sintax. Usualmente uso métodos de extensión; pero contiene funcionará.

+0

Excepto que contiene ajustará automáticamente todo el término de búsqueda en comodines. ¿Qué pasa si el usuario quiere que todas las personas cuyo nombre empieza con "Mar" Mar * regresó María Marissa Omar Jamaraquoui (Los nombres han sido cambiados para proteger a los inocentes) – esac

+0

lo que es aún más extraño es que se está agregando un '~' también. Para un término de búsqueda en blanco, searchTerm es "%". Cuando consulta la base de datos, esto es lo que Contiene lo convierte en: @ p__linq__2 = N '% ~ %%' – esac

+0

El ~ probablemente se esté utilizando como un carácter de escape para mostrar que está buscando cadenas con el literal "%" dentro de él . Si va a usar Contiene (que maneja el cardado comodín), entonces no puede tratar de manejar el cardado comodín. –

8

Bueno, sus opciones son:

  • Uso Contains. Sé que no te gusta, pero probablemente podría funcionar.
  • Elija una función de SqlFunctions. Todos son compatibles con L2E.
  • Map your own function.
  • +1 a @Yury para ESQL.
+0

No me gusta Contiene. No funciona como estaba previsto, consulte mi respuesta a continuación a Mike M. No hay nada en SqlFunctions que incluya una cláusula LIKE. El mapa de su propia función es obvio, y es esencialmente lo que estaba haciendo de todos modos, pero parece como este es un simple preguntar que sería compatible de forma nativa. – esac

+1

Entre 'Contains',' StartsWith', y 'EndsWith' puedes elegir qué comodines necesitas. Creo que cubre todos tus casos. –

+0

Sí, usaría Contiene, StartsWith y EndsWith - ESOS SQLMETHODS para LIKE son demasiado escamosos –

0

Incluso se puede añadir soporte para un método .Como() dentro de LINQ a Entidades para entonces, en lugar de la propuesta (y trabajar)

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

es sólo

var people = entities.People.Where(p => p.Name.Like(searchTerm)); 

Ver http://jendaperl.blogspot.com/2011/02/like-in-linq-to-entities.html

3

Usted puede hacer esto:

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

porque LINQ a Entity no puede transformar el método Contains() al SQL, pero LINQ a SQL puede hacer esto. Traté de encontrar un método que pueda hacer un cast, al fin, AsQueryable(), también una versión genérica AsQueryable<T>(). Descubrí que puedo hacer esto utilizándolo de esta manera en mi caso, pero no sé si tiene algún efecto colateral, tal vez perderá alguna función al Entity.

12

Cómo conseguir que funcione a la perfección:

en su modelo EDMX, añadir:

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

justo después de las secciones que se inician:

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

Entonces, en cualquier parte su código, agregue este método de extensión:

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

Y ya lo tienes.

Ahora se puede hacer:

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

o

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

test.Where(t=> t.Like("%yd%e%")).Dump(); 
+1

El método especificado 'Boolean Like (System.String, System.String)' en el tipo '... SearcherHelper' no se puede traducir a una expresión de almacenamiento LINQ to Entities. :( – Gary

+0

No entiendo cómo funciona esto porque en mi caso la aplicación no ejecuta el método de extensión ... ninguna descripción detallada sobre el funcionamiento? – Kimbo

+0

Las líneas EDMX (arriba) lo harán funcionar con LINQ para Entidades. LINQ a las entidades, el método se llamará – mlipman

0

usted puede hacer todas estas declaraciones con LINQ como esto

string _search = "blow"; 
// 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

la solución es utilizar SQLFunctions.PatIndex

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

donde 'searchstring' es el patrón para buscar 'fieldtoSearch' es el campo para buscar

patindex() permite la búsqueda mediante la búsqueda patrón de encordado. La búsqueda no distingue entre mayúsculas y minúsculas.

0

No necesita utilizar el signo de porcentaje durante el filtrado. p.ej;

si quiero comprobar NombreDeElemento no contiene '-' Voy a hacerlo de esta manera

Item.ItemName.Contains! ("-")

En SQL que convertirá a no me gusta ' % -% '

0

Utilizamos Database First y EntityFramework.

"Asigna tu propia función". el acercamiento funciona para nosotros junto con el nuget EntityFramework.CodeFirstStoreFunctions.

1 Paso: Crear una función en el PP como esto:

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 Paso: Instalar EntityFramework.CodeFirstStoreFunctions NuGet

3 Paso: Crear un método en su código como este (creo mía en la clase DbContext):

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

4 Paso: inicializar EntityFramework.CodeFirstStoreFunctions.

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

5 Paso: Ahora puede utilizar este método en su consulta linq.

Cuestiones relacionadas