Operador LIKE en LINQ

¿Hay alguna forma de comparar cadenas en una expresión C # LINQ similar al operador LIKE de SQL?

Supongamos que tengo una lista de cuerdas. En esta lista, quiero buscar una cadena. En SQL, podría escribir:

 SELECT * FROM DischargePort WHERE PortName LIKE '%BALTIMORE%' 

En lugar de lo anterior, la consulta quiere una syntax de linq.

 using System.Text.RegularExpressions; … var regex = new Regex(sDischargePort, RegexOptions.IgnoreCase); var sPortCode = Database.DischargePorts .Where(p => regex.IsMatch(p.PortName)) .Single().PortCode; 

Mi syntax de LINQ anterior no funciona. ¿Qué tengo mal?

Por lo general, utiliza String.StartsWith / EndsWith / Contains . Por ejemplo:

 var portCode = Database.DischargePorts .Where(p => p.PortName.Contains("BALTIMORE")) .Single() .PortCode; 

No sé si hay una manera de hacer expresiones regulares apropiadas a través de LINQ to SQL. (Tenga en cuenta que realmente depende del proveedor que esté utilizando; estaría bien en LINQ to Objects; se trata de si el proveedor puede convertir la llamada a su formato de consulta original, por ejemplo, SQL).

EDITAR: Como dice BitKFu, Single debe usarse cuando esperas exactamente un resultado, cuando es un error no ser así. Las opciones de SingleOrDefault , FirstOrDefault o First deben usarse dependiendo de lo que se espera exactamente .

Regex? no. Pero para esa consulta solo puede usar:

  string filter = "BALTIMORE"; (blah) .Where(row => row.PortName.Contains(filter)) (blah) 

Si realmente desea SQL LIKE , puede usar System.Data.Linq.SqlClient.SqlMethods.Like(...) , que LINQ-to-SQL asigna a LIKE en SQL Server.

Como Jon Skeet y Marc Gravell ya mencionaron, puedes simplemente tomar una condición de contener. Pero en el caso de su consulta similar, es muy peligroso tomar una statement Single (), porque eso implica que solo encontrará 1 resultado. En caso de obtener más resultados, recibirá una buena excepción 🙂

Entonces preferiría usar FirstOrDefault () en lugar de Single ():

 var first = Database.DischargePorts.FirstOrDefault(p => p.PortName.Contains("BALTIMORE")); var portcode = first != null ? first.PortCode : string.Empty; 

Bueno … a veces puede ser incómodo usar Contains , StartsWith o EndsWith especialmente cuando el valor de búsqueda determina una statement LIKE por ejemplo, pasa el ‘valor%’ requerido por el desarrollador para usar la función StartsWith en la expresión. Así que decidí escribir extensión para objetos IQueryable .

Uso

 // numbers: 11-000-00, 00-111-00, 00-000-11 var data1 = parts.Like(p => p.Number, "%11%"); // result: 11-000-00, 00-111-00, 00-000-11 var data2 = parts.Like(p => p.Number, "11%"); // result: 11-000-00 var data3 = parts.Like(p => p.Number, "%11"); // result: 00-000-11 

Código

 public static class LinqEx { private static readonly MethodInfo ContainsMethod = typeof(string).GetMethod("Contains"); private static readonly MethodInfo StartsWithMethod = typeof(string).GetMethod("StartsWith", new[] { typeof(string) }); private static readonly MethodInfo EndsWithMethod = typeof(string).GetMethod("EndsWith", new[] { typeof(string) }); public static Expression> LikeExpression(Expression> property, string value) { var param = Expression.Parameter(typeof(TSource), "t"); var propertyInfo = GetPropertyInfo(property); var member = Expression.Property(param, propertyInfo.Name); var startWith = value.StartsWith("%"); var endsWith = value.EndsWith("%"); if (startWith) value = value.Remove(0, 1); if (endsWith) value = value.Remove(value.Length - 1, 1); var constant = Expression.Constant(value); Expression exp; if (endsWith && startWith) { exp = Expression.Call(member, ContainsMethod, constant); } else if (startWith) { exp = Expression.Call(member, EndsWithMethod, constant); } else if (endsWith) { exp = Expression.Call(member, StartsWithMethod, constant); } else { exp = Expression.Equal(member, constant); } return Expression.Lambda>(exp, param); } public static IQueryable Like(this IQueryable source, Expression> parameter, string value) { return source.Where(LikeExpression(parameter, value)); } private static PropertyInfo GetPropertyInfo(Expression expression) { var lambda = expression as LambdaExpression; if (lambda == null) throw new ArgumentNullException("expression"); MemberExpression memberExpr = null; switch (lambda.Body.NodeType) { case ExpressionType.Convert: memberExpr = ((UnaryExpression)lambda.Body).Operand as MemberExpression; break; case ExpressionType.MemberAccess: memberExpr = lambda.Body as MemberExpression; break; } if (memberExpr == null) throw new InvalidOperationException("Specified expression is invalid. Unable to determine property info from expression."); var output = memberExpr.Member as PropertyInfo; if (output == null) throw new InvalidOperationException("Specified expression is invalid. Unable to determine property info from expression."); return output; } } 

En LINQ nativo puede usar una combinación de Contains/StartsWith/EndsWith o RegExp.

En LINQ2SQL use el método SqlMethods.Like()

  from i in db.myTable where SqlMethods.Like(i.field, "tra%ata") select i 

agregue Assembly: System.Data.Linq (en System.Data.Linq.dll) para usar esta característica.

Un simple como este

 string[] users = new string[] {"Paul","Steve","Annick","Yannick"}; var result = from u in users where u.Contains("nn") select u; 

Resultado -> Annick, Yannick

Puede llamar al método único con un predicado:

 var portCode = Database.DischargePorts .Single(p => p.PortName.Contains("BALTIMORE")) .PortCode; 
  .Where(e => e.Value.StartsWith("BALTIMORE")) 

Esto funciona como “ME GUSTA” de SQL …

Lo ideal sería usar StartWith o EndWith .

Aquí hay un ejemplo:

 DataContext dc = new DCGeneral(); List lstPerson= dc.GetTable().StartWith(c=> c.strNombre).ToList(); return lstPerson; 
  public static class StringEx { public static bool Contains(this String str, string[] Arr, StringComparison comp) { if (Arr != null) { foreach (string s in Arr) { if (str.IndexOf(s, comp)>=0) { return true; } } } return false; } public static bool Contains(this String str,string[] Arr) { if (Arr != null) { foreach (string s in Arr) { if (str.Contains(s)) { return true; } } } return false; } } var portCode = Database.DischargePorts .Single(p => p.PortName.Contains( new string[] {"BALTIMORE"}, StringComparison.CurrentCultureIgnoreCase) )) .PortCode; 

Solo agregue a los métodos de extensión de objeto de cadena.

 public static class StringEx { public static bool Contains(this String str, string[] Arr, StringComparison comp) { if (Arr != null) { foreach (string s in Arr) { if (str.IndexOf(s, comp)>=0) { return true; } } } return false; } public static bool Contains(this String str,string[] Arr) { if (Arr != null) { foreach (string s in Arr) { if (str.Contains(s)) { return true; } } } return false; } } 

uso:

 use namespase that contains this class; var sPortCode = Database.DischargePorts .Where(p => p.PortName.Contains(new string [] {"BALTIMORE"}, StringComparison.CurrentCultureIgnoreCase) ) .Single().PortCode; 

Encontré una solución para imitar al operador SQL LIKE. Consulte la respuesta que he escrito aquí https://stackoverflow.com/a/46592475/1186073