Czy istnieje sposób, aby porównać ciągi w wyrażeniu C # LINQ podobnym do LIKE
operatora SQL ?
Załóżmy, że mam listę ciągów. Na tej liście chcę wyszukać ciąg. W SQL mógłbym napisać:
SELECT * FROM DischargePort WHERE PortName LIKE '%BALTIMORE%'
Zamiast powyższego, zapytanie wymaga składni linq.
using System.Text.RegularExpressions;
…
var regex = new Regex(sDischargePort, RegexOptions.IgnoreCase);
var sPortCode = Database.DischargePorts
.Where(p => regex.IsMatch(p.PortName))
.Single().PortCode;
Moja powyższa składnia LINQ nie działa. Co się stało?
Odpowiedzi:
Zwykle używasz
String.StartsWith
/EndsWith
/Contains
. Na przykład:var portCode = Database.DischargePorts .Where(p => p.PortName.Contains("BALTIMORE")) .Single() .PortCode;
Nie wiem jednak, czy istnieje sposób na wykonanie odpowiednich wyrażeń regularnych za pośrednictwem LINQ to SQL. (Zauważ, że tak naprawdę zależy to od dostawcy, którego używasz - byłoby dobrze w LINQ to Objects; jest to kwestia tego, czy dostawca może przekonwertować wywołanie na jego natywny format zapytania, np. SQL).
EDYCJA: Jak mówi BitKFu,
Single
powinno być używane, gdy oczekujesz dokładnie jednego wyniku - jeśli jest to błąd, aby tak nie było. OpcjeSingleOrDefault
,FirstOrDefault
czyFirst
należy stosować w zależności od dokładnie , co się spodziewać.źródło
Single()
,SingleOrDefault()
byłby moim następnym krokiem, chyba że rozumiemy pełny kontekst ...Regex? Nie. Ale do tego zapytania możesz po prostu użyć:
string filter = "BALTIMORE"; (blah) .Where(row => row.PortName.Contains(filter)) (blah)
Jeśli naprawdę chcesz SQL
LIKE
, możesz użyćSystem.Data.Linq.SqlClient.SqlMethods.Like(...)
mapowania LINQ-to-SQLLIKE
w SQL Server.źródło
Cóż ... czasami może być niewygodne w użyciu
Contains
,StartsWith
aEndsWith
zwłaszcza gdy wyszukiwanie wartości określaLIKE
instrukcję, np. Przekazana „wartość%” wymaga od programisty użyciaStartsWith
funkcji w wyrażeniu. Postanowiłem więc napisać rozszerzenie dlaIQueryable
obiektów.Stosowanie
// 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
Kod
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; } }
źródło
IEnumerable
?Jak już wspomnieli Jon Skeet i Marc Gravell, możesz po prostu wziąć warunek zawierający. Ale w przypadku podobnego zapytania bardzo niebezpieczne jest wykonanie instrukcji Single (), ponieważ oznacza to, że znajdziesz tylko 1 wynik. W przypadku większej ilości wyników otrzymasz miły wyjątek :)
Więc wolałbym używać FirstOrDefault () zamiast Single ():
var first = Database.DischargePorts.FirstOrDefault(p => p.PortName.Contains("BALTIMORE")); var portcode = first != null ? first.PortCode : string.Empty;
źródło
W natywnym LINQ możesz użyć kombinacji
Contains/StartsWith/EndsWith
lub RegExp.W LINQ2SQL użyj metody
SqlMethods.Like()
from i in db.myTable where SqlMethods.Like(i.field, "tra%ata") select i
dodaj Assembly: System.Data.Linq (w System.Data.Linq.dll), aby użyć tej funkcji.
źródło
StartsWith()
,Contains()
itd, czy nie praca z linq2sql (przynajmniej mam „Wyrażenie LINQ ... nie można przetłumaczyć ...” i nakłanianie do użycia ToList () dla „klient” ewaluacji-co ja” m już robię. Uwaga, w EF Core jest przeniesiony doEF.Functions.Like()
.Where(e => e.Value.StartsWith("BALTIMORE"))
To działa jak „LIKE” w SQL ...
źródło
Takie proste
string[] users = new string[] {"Paul","Steve","Annick","Yannick"}; var result = from u in users where u.Contains("nn") select u;
Wynik -> Annick, Yannick
źródło
Możesz wywołać pojedynczą metodę z predykatem:
var portCode = Database.DischargePorts .Single(p => p.PortName.Contains("BALTIMORE")) .PortCode;
źródło
Najlepiej byłoby użyć
StartWith
lubEndWith
.Oto przykład:
DataContext dc = new DCGeneral(); List<Person> lstPerson= dc.GetTable<Person>().StartWith(c=> c.strNombre).ToList(); return lstPerson;
źródło
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;
źródło
Po prostu dodaj metody rozszerzania obiektów typu string.
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; } }
stosowanie:
use namespase that contains this class; var sPortCode = Database.DischargePorts .Where(p => p.PortName.Contains(new string [] {"BALTIMORE"}, StringComparison.CurrentCultureIgnoreCase) ) .Single().PortCode;
źródło
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();
źródło
@adobrzyc miał tę świetną niestandardową
LIKE
funkcję - chciałem tylko udostępnić jejIEnumerable
wersję.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; } }
źródło