¿Hay alguna forma de comparar cadenas en una expresión C # LINQ similar al LIKE
operador de SQL ?
Supongamos que tengo una lista de cadenas. 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 sintaxis 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 sintaxis LINQ anterior no funciona. ¿Qué me he equivocado?
Respuestas:
Normalmente usa
String.StartsWith
/EndsWith
/Contains
. Por ejemplo:var portCode = Database.DischargePorts .Where(p => p.PortName.Contains("BALTIMORE")) .Single() .PortCode;
Sin embargo, no sé si hay una forma de hacer expresiones regulares adecuadas 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; es una cuestión de si el proveedor puede convertir la llamada a su formato de consulta nativo, por ejemplo, SQL).
EDITAR: Como dice BitKFu,
Single
debe usarse cuando espera exactamente un resultado, cuando es un error para que ese no sea el caso. Opciones deSingleOrDefault
,FirstOrDefault
oFirst
deberían usarse dependiendo exactamente de lo que se espera.fuente
Single()
,SingleOrDefault()
sería mi próximo paso, a menos que comprendamos el contexto completo ...¿Regex? No. Pero para esa consulta puedes usar:
string filter = "BALTIMORE"; (blah) .Where(row => row.PortName.Contains(filter)) (blah)
Si realmente desea SQL
LIKE
, puede usarSystem.Data.Linq.SqlClient.SqlMethods.Like(...)
, a qué asigna LINQ-to-SQLLIKE
en SQL Server.fuente
Bueno ... a veces puede ser incómodo de usar
Contains
,StartsWith
oEndsWith
especialmente cuando se busca un valor de determinación,LIKE
por ejemplo, el 'valor%' pasado requiere que el desarrollador use laStartsWith
función en la expresión. Entonces decidí escribir extensión paraIQueryable
objetos.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<Func<TSource, bool>> LikeExpression<TSource, TMember>(Expression<Func<TSource, TMember>> 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<Func<TSource, bool>>(exp, param); } public static IQueryable<TSource> Like<TSource, TMember>(this IQueryable<TSource> source, Expression<Func<TSource, TMember>> 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; } }
fuente
IEnumerable
?Como ya mencionaron Jon Skeet y Marc Gravell, simplemente puede tomar una condición contiene. Pero en el caso de su consulta similar, es muy peligroso tomar una declaración Single (), porque eso implica que solo encuentra 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;
fuente
En LINQ nativo, puede utilizar una combinación de
Contains/StartsWith/EndsWith
o RegExp.En el método de uso de LINQ2SQL
SqlMethods.Like()
from i in db.myTable where SqlMethods.Like(i.field, "tra%ata") select i
agregue Ensamblado: System.Data.Linq (en System.Data.Linq.dll) para usar esta función.
fuente
StartsWith()
,Contains()
, etc, qué no trabajo con Linq2SQL (al menos me sale "La expresión LINQ ... no se podría traducir ..." y una instrucción para el uso ToList () para "evaluación del cliente", lo que yo' . m Nota haciendo ya, en EF Core, se trasladó aEF.Functions.Like()
.Where(e => e.Value.StartsWith("BALTIMORE"))
Esto funciona como "LIKE" de SQL ...
fuente
Tan simple como esto
string[] users = new string[] {"Paul","Steve","Annick","Yannick"}; var result = from u in users where u.Contains("nn") select u;
Resultado -> Annick, Yannick
fuente
Puede llamar al método único con un predicado:
var portCode = Database.DischargePorts .Single(p => p.PortName.Contains("BALTIMORE")) .PortCode;
fuente
Lo ideal sería utilizar
StartWith
oEndWith
.Aquí hay un ejemplo:
DataContext dc = new DCGeneral(); List<Person> lstPerson= dc.GetTable<Person>().StartWith(c=> c.strNombre).ToList(); return lstPerson;
fuente
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;
fuente
Simplemente agregue a los métodos de extensión de objetos 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;
fuente
List<Categories> categoriess; private void Buscar() { try { categoriess = Contexto.Categories.ToList(); categoriess = categoriess.Where(n => n.CategoryID >= Convert.ToInt32(txtCatID.Text) && n.CategoryID <= Convert.ToInt32(txtCatID1.Text) && (n.CategoryName.Contains(txtCatName.Text)) ).ToList();
fuente
@adobrzyc tenía esta gran
LIKE
función personalizada , solo quería compartir laIEnumerable
versión.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) }); private static Func<TSource, bool> LikeExpression<TSource, TMember>(Expression<Func<TSource, TMember>> 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<Func<TSource, bool>>(exp, param).Compile(); } public static IEnumerable<TSource> Like<TSource, TMember>(this IEnumerable<TSource> source, Expression<Func<TSource, TMember>> 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; } }
fuente