Pregunta

Me gustaría saber si es posible hacer una búsqueda con comodín utilizando LINQ.

Veo que LINQ tiene Contains, StartsWith, EndsWith, etc.

¿Qué sucede si quiero algo como% Prueba si% funciona%, cómo lo hago?

Saludos

¿Fue útil?

Solución

Usaría Expresiones regulares, ya que es posible que no siempre estés usando Linq to SQL.

Como este ejemplo de Linq to Objects

List<string> list = new List<string>();
list.Add("This is a sentence.");
list.Add("This is another one.");
list.Add("C# is fun.");
list.Add("Linq is also fun.");

System.Text.RegularExpressions.Regex regEx = new System.Text.RegularExpressions.Regex("This");

var qry = list
    .Where<string>(item => regEx.IsMatch(item))
    .ToList<string>();

// Print results
foreach (var item in qry)
{
    Console.WriteLine(item);
}

Otros consejos

Puede usar SqlMethods.Like () .

Un ejemplo del uso:

var results =
        from u in users
        where SqlMethods.Like(u.FirstName, "%John%")
        select u;

agregue System.Data.Linq.SqlClient a su lista de uso o importación e intente:

var results= from x in data
             where SqlMethods.Like(x.SearchField, “%something%like%this%”)
             select x;

Para Entity Framework Core 2.0 hay un operador LIKE ( anunciado en agosto de 2017 ):

var query = from e in _context.Employees
                    where EF.Functions.Like(e.Title, "%developer%")
                    select e;

Mirando la pregunta

  

¿Qué sucede si quiero algo como% Prueba si% funciona%, cómo lo hago?

entonces espero algo de

LIKE '%Test if%it work%'

significa que la cadena debe contener 'Probar si' y 'funciona', en ese orden .

Esto no funcionará:

context.SomeTable.Where(s => s.Name.Contains("Test if%it work")).ToList();

Y si uso:

context.SomeTable.Where(s => s.Name.Contains("Test if") && s.Name.Contains("it work")).ToList();

entonces encontraré todos los registros que contengan ambos "Probar si" y " funciona " ;, pero no específicamente en ese orden .

Entonces, con Contiene esto no es posible. Pero con IndexOf lo es.

IndexOf localizará la cadena de búsqueda Y devolverá su posición en la cadena. Haciendo posible encontrar las palabras en el orden correcto.

- Actualización -

Con mi respuesta original, mi objetivo no era proporcionar una solución genérica, sino más bien un ejemplo de otro enfoque que no depende de SQL. Por lo tanto, es correcto que el ejemplo original solo responda a la pregunta literal. Pero dado que la respuesta puede ser más útil si es genérica, he escrito una extensión IQuerable que permite agregar una declaración similar a la consulta tan fácil como una declaración where. La extensión funciona tanto para Linq como para Linq-Sql.

Esto encontrará todos los registros con ambos " Probar si " y "funciona", en ese orden.

context.SomeTable.Like("test if%it work", "Name").ToList();

listOfString.Like("test if%it work").ToList();

Extensión, permite cualquier número de comodines:

/// <summary>
/// Allow to search the string with wildcards.
/// </summary>
/// <typeparam name="T">String or an object with a string member.</typeparam>
/// <param name="q">Original query</param>
/// <param name="searchstring">The searchstring</param>
/// <param name="memberName">The name of the field or null if not a field.</param>
/// <returns>Query filtered by 'LIKE'.</returns>
public static IQueryable<T> Like<T>(this IQueryable<T> q, string searchstring, string memberName = null)
{
    // %a%b%c% --> IndexOf(a) > -1 && IndexOf(b) > IndexOf(a) && IndexOf(c) > IndexOf(b)

    var eParam = Expression.Parameter(typeof(T), "e");

    MethodInfo methodInfo;

    // Linq (C#) is case sensitive, but sql isn't. Use StringComparison ignorecase for Linq.
    // Sql however doesn't know StringComparison, so try to determine the provider.
    var isLinq = (q.Provider.GetType().IsGenericType && q.Provider.GetType().GetGenericTypeDefinition() == typeof(EnumerableQuery<>));
    if (isLinq)
        methodInfo = typeof(string).GetMethod("IndexOf", new[] { typeof(string), typeof(StringComparison) });
    else
        methodInfo = typeof(string).GetMethod("IndexOf", new[] { typeof(string) });

    Expression expr;
    if (string.IsNullOrEmpty(memberName))
        expr = eParam;
    else
        expr = Expression.Property(eParam, memberName);

    // Split the searchstring by the wildcard symbol:
    var likeParts = searchstring.Split(new char[] { '%' }, StringSplitOptions.RemoveEmptyEntries);

    for (int i = 0; i < likeParts.Length; i++)
    {
        MethodCallExpression e;
        if (isLinq)
            e = Expression.Call(expr, methodInfo, new Expression[] { Expression.Constant(likeParts[i], typeof(string)), Expression.Constant(StringComparison.OrdinalIgnoreCase) });
        else
            e = Expression.Call(expr, methodInfo, Expression.Constant(likeParts[i], typeof(string)));

        if (i == 0)
        {
            // e.IndexOf("likePart") > -1
            q = q.Where(Expression.Lambda<Func<T, bool>>(Expression.GreaterThan(e, Expression.Constant(-1, typeof(int))), eParam));
        }
        else
        {
            // e.IndexOf("likePart_previous")
            MethodCallExpression ePrevious;
            if (isLinq)
                ePrevious = Expression.Call(expr, methodInfo, new Expression[] { Expression.Constant(likeParts[i - 1], typeof(string)), Expression.Constant(StringComparison.OrdinalIgnoreCase) });
            else
                ePrevious = Expression.Call(expr, methodInfo, Expression.Constant(likeParts[i - 1], typeof(string)));

            // e.IndexOf("likePart_previous") < e.IndexOf("likePart")
            q = q.Where(Expression.Lambda<Func<T, bool>>(Expression.LessThan(ePrevious, e), eParam));
        }
    }
    return q;
}

Dado que no necesita métodos Sql, supongo que puede usar esto para cualquier base de datos, como MySql o Postgresql. Pero no estoy seguro. Probé esto con SQL Server usando Entity Framework 6. La declaración anterior genera el siguiente código en SQL Server.

SELECT [Extent1].* FROM SomeTable AS [Extent1]
WHERE ((( CAST(CHARINDEX(N'test if', [Extent1].[Name]) AS int)) - 1) > -1)
AND ((( CAST(CHARINDEX(N'test if', [Extent1].[Name]) AS int)) - 1) < 
     (( CAST(CHARINDEX(N'it work', [Extent1].[Name]) AS int)) - 1))

Sobre el rendimiento, parece haber alguna discusión sobre lo que es "mejor": LIKE o CHARINDEX. Y por lo que he leído, CHARINDEX parece ser el favorito.

.Where( column LIKE "Pattern")
var result = (from x in db.Members
              where x.IDNumber.Contains(idnumber)
              && x.InstitutionIdentifier == institution.Identifier
              select x).ToList();
return result;

Funcionará tanto para Linq to SQL como para Linq en la memoria.

Sé que este es un tema antiguo, pero aquí está mi solución muy simple:

string s=Regex.Escape("pattern - escaped for sanity").Replace("%", ".*").Replace("_", ".?");
user => Regex.IsMatch(user.FullName, s, RegexOptions.CultureInvariant | RegexOptions.IgnoreCase);

En este código, estoy usando caracteres de escape comunes para el lenguaje SQL. Si desea utilizar decir * y ? , la cadena de escape contendrá \ * y \? correspondientemente, haga asegúrese de incluir el carácter barra diagonal inversa en la (s) declaración (s) .Replace (...) . Por supuesto, si desea darle a su usuario la capacidad de búsqueda RexEx, simplemente no escape de la cadena de patrón.

Busca el tutorial de Regex para otras opciones.

Creo que normalmente % coincidirá con al menos un carácter , mientras que RegEx . * coincidirá con cero o más personajes. Entonces, en realidad, el comodín % es más como . + (codicioso) en lugar de . * (perezoso).

Espero que esto ayude.

no estoy seguro si hablas LinqToSql o simplemente linq ... pero podrías expresiones regulares como esta:

.Where(dto => System.Text.RegularExpressions.Regex.IsMatch(dto.CustomerName, @"Ad"));

En el código .Net que incluye LINQ to Objects, estoy usando la implementación de la función IsSqlLikeMatch del hilo Uso de Regex para crear un" like "de SQL como la función. .

Ejemplo de uso

bool ret = message.IsSqlLikeMatch(pattern);

Más detalles en mi publicación SQL's " like " ; patrones para comparar en .Net

También puede usar " contiene "

var myresult = db.MyItems.Where(x=>x.MyField.Contains(mysearchstring));

¿Estás hablando de LINQ a objetos o LINQ a SQL?

Para LINQ to object, deberá recurrir a expresiones regulares me piensa.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top