¿Cómo hacer SQL Like% en Linq?


385

Tengo un procedimiento en SQL que estoy tratando de convertir en Linq:

SELECT O.Id, O.Name as Organization
FROM Organizations O
JOIN OrganizationsHierarchy OH ON O.Id=OH.OrganizationsId
where OH.Hierarchy like '%/12/%'

La línea que más me preocupa es:

where OH.Hierarchy like '%/12/%'

Tengo una columna que almacena la jerarquía como / 1/3/12 / por ejemplo, así que solo uso% / 12 /% para buscarla.

Mi pregunta es, ¿cuál es el equivalente de Linq o .NET para usar el signo de porcentaje?


1
Su pregunta tiene al menos 5votos para la etiqueta de operador similar . ¿Podría solicitar amablemente que sugiera sql-like como sinónimo ?
Kermit

Respuestas:


550
.Where(oh => oh.Hierarchy.Contains("/12/"))

También puedes usar .StartsWith()o .EndsWith().


44
¿Usar StartsWith () o EndsWith () disparará una consulta? Quiero decir, ¿el código se traducirá en una consulta o los resultados se filtrarán en el objeto después de la recuperación de la base de datos?
Novicio

55
No. StartsWith () y EndsWith () son parte del predicado / filtro. La ejecución continúa siendo diferida.
andleer

2
intentado que obtuvo NullReferenceException: referencia de objeto no establecida en una instancia de un objeto. Entonces no me gusta cuando en mi caso a.Address1.StartsWith (Address1) y a.Address1 es nulo
MikeT

11
StartsWith("abc")se convierte LIKE 'abc%'y EndsWith("abc")se convierte enLIKE '%abc'
Simon_Weaver

20
No se pudo entender por qué esto no funcionaba para un caso de uso con letras, luego me di cuenta de mi estupidez ... no olvides, .ToLower().Contains()etc., si quieres ignorar el caso. Si lo desea, por supuesto, dependerá de si está tratando de imitar LIKE desde una base de datos con intercalación entre mayúsculas y minúsculas o no.
Adam Knights

251

Utilizar este:

from c in dc.Organization
where SqlMethods.Like(c.Hierarchy, "%/12/%")
select *;

22
Esto es realmente útil si desea utilizar la coincidencia de patrones más complicada proporcionada por el comando like. Por ejemplo, si desea verificar dos números (en lugar de 12), puede usar esta expresión: SqlMethods.Like (c.Hierarchy, "% / [0-9] [0-9] /%") También , vea esto msdn.microsoft.com/en-us/library/aa933232(SQL.80).aspx
viggity

esto también es muy útil si desea permitir a los usuarios avanzados que ahorren el costoso% inicial ellos mismos, donde usar StartsWith o Contains no le da al usuario
avanzado

8
¿Cómo se usa el SqlMethodsuso de "notación de puntos"?
dan-gph

12
Tenga en cuenta que debe incluir el System.Data.Linq.SqlClientespacio de nombres.
johna

1
No pude encontrar System.Data.Linq.SqlClient aunque puedo agregar System.Data.Linq. ¿Está en desuso?
Burak Karakuş

41

Supongo que está utilizando Linq-to-SQL * (vea la nota a continuación). Si es así, use string.Contains, string.StartsWith y string.EndsWith para generar SQL que use el operador SQL LIKE.

from o in dc.Organization
join oh in dc.OrganizationsHierarchy on o.Id equals oh.OrganizationsId
where oh.Hierarchy.Contains(@"/12/")
select new { o.Id, o.Name }

o

from o in dc.Organization
where o.OrganizationsHierarchy.Hierarchy.Contains(@"/12/")
select new { o.Id, o.Name }

Nota: * = si está utilizando ADO.Net Entity Framework (EF / L2E) en .net 3.5, tenga en cuenta que no realizará la misma traducción que Linq-to-SQL. Aunque L2S hace una traducción adecuada, L2E v1 (3.5) se traducirá en una expresión t-sql que forzará un escaneo completo de la tabla que está consultando a menos que haya otro discriminador mejor en su cláusula where o filtros de unión.
Actualización: Esto se corrige en EF / L2E v4 (.net 4.0), por lo que generará un LIKE de SQL como lo hace L2S.


No es necesario escapar de sus hilos con el @signo, pero me doy cuenta de que esto puede ser una buena convención a seguir.
andleer

27

Si está utilizando VB.NET, la respuesta sería "*". Así es como se vería su cláusula where ...

Where OH.Hierarchy Like '*/12/*'

Nota: "*" Coincide con cero o más caracteres. Aquí está el artículo de msdn para el operador Like .


¿El operador VB Like se traduce en llamadas L2S? (No tengo idea.)
andleer

8
Sí, el operador VB Like se traduce a la versión SQL de like cuando se usa en una expresión de consulta LINQ. Además, el operador VB Like no está restringido a expresiones de consulta.
robertz

1
Vi que existía fuera de las operaciones de LINQ. Buen material. +1
andleer

9

Bueno indexOf también funciona para mí

var result = from c in SampleList
where c.LongName.IndexOf(SearchQuery) >= 0
select c;

1
Esta debería ser la respuesta aceptada. IndexOf se traduce a CHARINDEX en sql. Esto posiblemente puede ser más rápido que LIKE. Pero aparte de eso, ofrece la posibilidad de construir consultas de búsqueda como '% some% thing%'. Donde 'algo' tiene que estar ubicado antes de 'cosa', lo que no se puede hacer con Contiene.
Ruard van Elburg

Me encanta cuando las respuestas que necesito tienen 8 años y escondieron varios niveles debajo de la respuesta aceptada. En pocas palabras, esto funcionó mientras que .Contains (@ "/ 12 /") y otras respuestas similares no. ¡Muy apreciado!
IdusOrtus

4

Usa dicho código

try
{
    using (DatosDataContext dtc = new DatosDataContext())
    {
        var query = from pe in dtc.Personal_Hgo
                    where SqlMethods.Like(pe.nombre, "%" + txtNombre.Text + "%")
                    select new
                    {
                        pe.numero
                        ,
                        pe.nombre
                    };
        dgvDatos.DataSource = query.ToList();
    }
}
catch (Exception ex)
{
    string mensaje = ex.Message;
}

4

.NET core ahora tiene EF.Functions.Like


¿Puedes explicar cómo usar esto para resolver el problema del OP?
Robert Columbia

ver, es decir, la respuesta de LP, es solo la versión principal de SqlMethods.Me gusta
kofifus

Esta respuesta debe contener un ejemplo práctico de cómo usar esta función.
FoxDeploy

3

En caso de que no coincida con cadenas numéricas, siempre es bueno tener un caso común:

.Where(oh => oh.Hierarchy.ToUpper().Contains(mySearchString.ToUpper()))

2

Siempre hago esto:

from h in OH
where h.Hierarchy.Contains("/12/")
select h

Sé que no uso la declaración similar, pero funciona bien en segundo plano, esto se traduce en una consulta con una declaración similar.


¿En qué se diferencia su respuesta de la respuesta aceptada (respondida hace 7 años) u otras respuestas? ¿Qué valor agrega?
David Ferenczy Rogožan

1
@DawidFerenczy Esta respuesta funciona con la sintaxis de consulta "from foo in bar", y la aceptada no.
nasch

1

Prueba esto, esto funciona bien para mí

from record in context.Organization where record.Hierarchy.Contains(12) select record;


0

Contiene se usa en Linq, al igual que Like se usa en SQL.

string _search="/12/";

. . .

.Where(s => s.Hierarchy.Contains(_search))

Puede escribir su script SQL en Linq de la siguiente manera:

 var result= Organizations.Join(OrganizationsHierarchy.Where(s=>s.Hierarchy.Contains("/12/")),s=>s.Id,s=>s.OrganizationsId,(org,orgH)=>new {org,orgH});

0

Para aquellos que caen aquí, como yo, buscando un método "SQL Like" en LINQ, tengo algo que funciona muy bien.

Estoy en un caso en el que no puedo alterar la base de datos de ninguna manera para cambiar la clasificación de columnas. Así que tengo que encontrar una manera en mi LINQ para hacerlo.

Estoy usando el método auxiliar SqlFunctions.PatIndex que actúa de manera similar al operador real SQL LIKE.

Primero necesito enumerar todos los diacríticos posibles (una palabra que acabo de aprender) en el valor de búsqueda para obtener algo como:

déjà     => d[éèêëeÉÈÊËE]j[aàâäAÀÂÄ]
montreal => montr[éèêëeÉÈÊËE][aàâäAÀÂÄ]l
montréal => montr[éèêëeÉÈÊËE][aàâäAÀÂÄ]l

y luego en LINQ por ejemplo:

var city = "montr[éèêëeÉÈÊËE][aàâäAÀÂÄ]l";
var data = (from loc in _context.Locations
                     where SqlFunctions.PatIndex(city, loc.City) > 0
                     select loc.City).ToList();

Entonces, para mis necesidades, he escrito un método de Ayuda / Extensión

   public static class SqlServerHelper
    {

        private static readonly List<KeyValuePair<string, string>> Diacritics = new List<KeyValuePair<string, string>>()
        {
            new KeyValuePair<string, string>("A", "aàâäAÀÂÄ"),
            new KeyValuePair<string, string>("E", "éèêëeÉÈÊËE"),
            new KeyValuePair<string, string>("U", "uûüùUÛÜÙ"),
            new KeyValuePair<string, string>("C", "cçCÇ"),
            new KeyValuePair<string, string>("I", "iîïIÎÏ"),
            new KeyValuePair<string, string>("O", "ôöÔÖ"),
            new KeyValuePair<string, string>("Y", "YŸÝýyÿ")
        };

        public static string EnumarateDiacritics(this string stringToDiatritics)
        {
            if (string.IsNullOrEmpty(stringToDiatritics.Trim()))
                return stringToDiatritics;

            var diacriticChecked = string.Empty;

            foreach (var c in stringToDiatritics.ToCharArray())
            {
                var diac = Diacritics.FirstOrDefault(o => o.Value.ToCharArray().Contains(c));
                if (string.IsNullOrEmpty(diac.Key))
                    continue;

                //Prevent from doing same letter/Diacritic more than one time
                if (diacriticChecked.Contains(diac.Key))
                    continue;

                diacriticChecked += diac.Key;

                stringToDiatritics = stringToDiatritics.Replace(c.ToString(), "[" + diac.Value + "]");
            }

            stringToDiatritics = "%" + stringToDiatritics + "%";
            return stringToDiatritics;
        }
    }

Si alguno de ustedes tiene sugerencias para mejorar este método, estaré encantado de escucharlo.


Su ejemplo es básicamente una colación insensible de acento casera. Una vez tuve que lidiar con un proyecto donde todas y cada una de las consultas pasaban por un filtro para lograr lo que una recopilación adecuada habría hecho automáticamente. Consulte stackoverflow.com/a/2461550/1736944 para conocer cuál es el mejor enfoque. Asigne la clasificación adecuada a la base de datos, tabla y / o campo, según se considere apropiado. (Trabajar sin una recopilación adecuada en el lugar es pura tortura)
9Rune5

0

Muy tarde, pero reuní esto para poder hacer comparaciones de cadenas usando comodines de estilo SQL Like:

public static class StringLikeExtensions
{
    /// <summary>
    /// Tests a string to be Like another string containing SQL Like style wildcards
    /// </summary>
    /// <param name="value">string to be searched</param>
    /// <param name="searchString">the search string containing wildcards</param>
    /// <returns>value.Like(searchString)</returns>
    /// <example>value.Like("a")</example>
    /// <example>value.Like("a%")</example>
    /// <example>value.Like("%b")</example>
    /// <example>value.Like("a%b")</example>
    /// <example>value.Like("a%b%c")</example>
    /// <remarks>base author -- Ruard van Elburg from StackOverflow, modifications by dvn</remarks>
    /// <remarks>converted to a String extension by sja</remarks>
    /// <seealso cref="/programming/1040380/wildcard-search-for-linq"/>
    public static bool Like(this String value, string searchString)
    {
        bool result = false;

        var likeParts = searchString.Split(new char[] { '%' });

        for (int i = 0; i < likeParts.Length; i++)
        {
            if (likeParts[i] == String.Empty)
            {
                continue;   // "a%"
            }

            if (i == 0)
            {
                if (likeParts.Length == 1) // "a"
                {
                    result = value.Equals(likeParts[i], StringComparison.OrdinalIgnoreCase);
                }
                else // "a%" or "a%b"
                {
                    result = value.StartsWith(likeParts[i], StringComparison.OrdinalIgnoreCase);
                }
            }
            else if (i == likeParts.Length - 1) // "a%b" or "%b"
            {
                result &= value.EndsWith(likeParts[i], StringComparison.OrdinalIgnoreCase);
            }
            else // "a%b%c"
            {
                int current = value.IndexOf(likeParts[i], StringComparison.OrdinalIgnoreCase);
                int previous = value.IndexOf(likeParts[i - 1], StringComparison.OrdinalIgnoreCase);
                result &= previous < current;
            }
        }

        return result;
    }

    /// <summary>
    /// Tests a string containing SQL Like style wildcards to be ReverseLike another string 
    /// </summary>
    /// <param name="value">search string containing wildcards</param>
    /// <param name="compareString">string to be compared</param>
    /// <returns>value.ReverseLike(compareString)</returns>
    /// <example>value.ReverseLike("a")</example>
    /// <example>value.ReverseLike("abc")</example>
    /// <example>value.ReverseLike("ab")</example>
    /// <example>value.ReverseLike("axb")</example>
    /// <example>value.ReverseLike("axbyc")</example>
    /// <remarks>reversed logic of Like String extension</remarks>
    public static bool ReverseLike(this String value, string compareString)
    {
        bool result = false;

        var likeParts = value.Split(new char[] {'%'});

        for (int i = 0; i < likeParts.Length; i++)
        {
            if (likeParts[i] == String.Empty)
            {
                continue;   // "a%"
            }

            if (i == 0)
            {
                if (likeParts.Length == 1) // "a"
                {
                    result = compareString.Equals(likeParts[i], StringComparison.OrdinalIgnoreCase);
                }
                else // "a%" or "a%b"
                {
                    result = compareString.StartsWith(likeParts[i], StringComparison.OrdinalIgnoreCase);
                }
            }
            else if (i == likeParts.Length - 1) // "a%b" or "%b"
            {
                result &= compareString.EndsWith(likeParts[i], StringComparison.OrdinalIgnoreCase);
            }
            else // "a%b%c"
            {
                int current = compareString.IndexOf(likeParts[i], StringComparison.OrdinalIgnoreCase);
                int previous = compareString.IndexOf(likeParts[i - 1], StringComparison.OrdinalIgnoreCase);
                result &= previous < current;
            }
        }

        return result;
    }
}
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.