[英]LIKE operator in LINQ
Is there any way to compare strings in a C# LINQ expression similar to SQL's LIKE
operator?有什么方法可以比较类似于 SQL 的LIKE
运算符的 C# LINQ 表达式中的字符串吗?
Suppose I have a string list.假设我有一个字符串列表。 On this list I want to search a string.在此列表中,我想搜索一个字符串。 In SQL, I could write:在 SQL 中,我可以这样写:
SELECT * FROM DischargePort WHERE PortName LIKE '%BALTIMORE%'
Instead of the above, query want a linq syntax.而不是上面的,查询需要一个 linq 语法。
using System.Text.RegularExpressions;
…
var regex = new Regex(sDischargePort, RegexOptions.IgnoreCase);
var sPortCode = Database.DischargePorts
.Where(p => regex.IsMatch(p.PortName))
.Single().PortCode;
My above LINQ syntax does not work.我上面的 LINQ 语法不起作用。 What have I got wrong?我做错了什么?
Typically you use String.StartsWith
/ EndsWith
/ Contains
.通常您使用String.StartsWith
/ EndsWith
/ Contains
。 For example:例如:
var portCode = Database.DischargePorts
.Where(p => p.PortName.Contains("BALTIMORE"))
.Single()
.PortCode;
I don't know if there's a way of doing proper regular expressions via LINQ to SQL though.我不知道是否有办法通过 LINQ to SQL 执行正确的正则表达式。 (Note that it really does depend on which provider you're using - it would be fine in LINQ to Objects; it's a matter of whether the provider can convert the call into its native query format, eg SQL.) (请注意,它确实取决于您使用的是哪个提供程序 - 在 LINQ to Objects 中会很好;这取决于提供程序是否可以将调用转换为其本机查询格式,例如 SQL。)
EDIT: As BitKFu says, Single
should be used when you expect exactly one result - when it's an error for that not to be the case.编辑:正如 BitKFu 所说,当您只期望一个结果时应该使用Single
- 当情况并非如此时是错误的。 Options of SingleOrDefault
, FirstOrDefault
or First
should be used depending on exactly what's expected.应根据预期使用SingleOrDefault
、 FirstOrDefault
或First
选项。
Regex?正则表达式? no.不。 But for that query you can just use:但是对于该查询,您可以使用:
string filter = "BALTIMORE";
(blah) .Where(row => row.PortName.Contains(filter)) (blah)
If you really want SQL LIKE
, you can use System.Data.Linq.SqlClient.SqlMethods.Like(...)
, which LINQ-to-SQL maps to LIKE
in SQL Server.如果你真的想要 SQL LIKE
,你可以使用System.Data.Linq.SqlClient.SqlMethods.Like(...)
,LINQ-to-SQL 映射到 SQL Server 中的LIKE
。
Well... sometimes it may be uncomfortable to use Contains
, StartsWith
or EndsWith
especially when searching value determine LIKE
statment eg passed 'value%' require from developer to use StartsWith
function in expression.好吧...有时使用Contains
、 StartsWith
或EndsWith
可能会让人不舒服,尤其是在搜索值确定LIKE
语句时,例如传递的 'value%' 要求开发人员在表达式中使用StartsWith
函数。 So I decided to write extension for IQueryable
objects.所以我决定为IQueryable
对象编写扩展。
Usage用法
// 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
Code代码
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;
}
}
In native LINQ you may use combination of Contains/StartsWith/EndsWith
or RegExp.在本机 LINQ 中,您可以使用Contains/StartsWith/EndsWith
或 RegExp 的组合。
In LINQ2SQL use method SqlMethods.Like()
在 LINQ2SQL 中使用方法SqlMethods.Like()
from i in db.myTable
where SqlMethods.Like(i.field, "tra%ata")
select i
add Assembly: System.Data.Linq (in System.Data.Linq.dll) to use this feature.添加程序集:System.Data.Linq(在 System.Data.Linq.dll 中)以使用此功能。
As Jon Skeet and Marc Gravell already mentioned, you can simple take a contains condition.正如 Jon Skeet 和 Marc Gravell 已经提到的,您可以简单地采用包含条件。 But in case of your like query, it's very dangerous to take a Single() statement, because that implies that you only find 1 result.但是对于你的 like 查询,采用 Single() 语句是非常危险的,因为这意味着你只能找到 1 个结果。 In case of more results, you'll receive a nice exception:)如果有更多结果,您将收到一个很好的例外:)
So I would prefer using FirstOrDefault() instead of Single():所以我更喜欢使用 FirstOrDefault() 而不是 Single():
var first = Database.DischargePorts.FirstOrDefault(p => p.PortName.Contains("BALTIMORE"));
var portcode = first != null ? first.PortCode : string.Empty;
A simple as this这么简单
string[] users = new string[] {"Paul","Steve","Annick","Yannick"};
var result = from u in users where u.Contains("nn") select u;
Result -> Annick,Yannick结果 -> Annick,Yannick
Ideally you should use StartWith
or EndWith
.理想情况下,您应该使用StartWith
或EndWith
。
Here is an example:这是一个例子:
DataContext dc = new DCGeneral();
List<Person> lstPerson= dc.GetTable<Person>().StartWith(c=> c.strNombre).ToList();
return lstPerson;
You can call the single method with a predicate:您可以使用谓词调用单个方法:
var portCode = Database.DischargePorts
.Single(p => p.PortName.Contains("BALTIMORE"))
.PortCode;
You can also use the EF function tested in .net5也可以使用.net5中测试过的EF函数
public async Task<IEnumerable<District>> SearchDistrict(string query, int stateId)
{
return await _dbContext
.Districts
.Include(s => s.State)
.Where(s => s.StateId == stateId && EF.Functions.Like(s.Name, "$%{query}%"))
.AsNoTracking()
.ToListAsync();
}
.Where(e => e.Value.StartsWith("BALTIMORE"))
This works like "LIKE" of SQL...这就像 SQL 的“LIKE”一样工作......
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();
Tested in .NET 5在 .NET 5 中测试
public static class LikeExtension {
private static string ColumnDataBase<TEntity, TKey>(IModel model, Expression<Func<TEntity, TKey>> predicate) where TEntity : class {
ITable table = model
.GetRelationalModel()
.Tables
.First(f => f
.EntityTypeMappings
.First()
.EntityType == model
.FindEntityType(predicate
.Parameters
.First()
.Type
));
string column = (predicate.Body as MemberExpression).Member.Name;
string columnDataBase = table.Columns.First(f => f.PropertyMappings.Count(f2 => f2.Property.Name == column) > 0).Name;
return columnDataBase;
}
public static IQueryable<TEntity> Like<TEntity, TKey>(this DbContext context, Expression<Func<TEntity, TKey>> predicate, string text) where TEntity : class {
string columnDataBase = ColumnDataBase(context.Model, predicate);
return context.Set<TEntity>().FromSqlRaw(context.Set<TEntity>().ToQueryString() + " WHERE [" + columnDataBase + "] LIKE {0}", text);
}
public static async Task<IEnumerable<TEntity>> LikeAsync<TEntity, TKey>(this DbContext context, Expression<Func<TEntity, TKey>> predicate, string text, CancellationToken cancellationToken) where TEntity : class {
string columnDataBase = ColumnDataBase(context.Model, predicate);
return await context.Set<TEntity>().FromSqlRaw(context.Set<TEntity>().ToQueryString() + " WHERE [" + columnDataBase + "] LIKE {0}", text).ToListAsync(cancellationToken);
}
public static async Task<IEnumerable<TEntity>> LikeAsync<TEntity, TKey>(this IQueryable<TEntity> query, Expression<Func<TEntity, TKey>> predicate, string text, CancellationToken cancellationToken) where TEntity : class {
DbSet<TEntity> entities = query as DbSet<TEntity>;
string columnDataBase = ColumnDataBase(entities.EntityType.Model, predicate);
return await entities.FromSqlRaw(query.ToQueryString() + " WHERE [" + columnDataBase + "] LIKE {0}", text).ToListAsync(cancellationToken);
}
public static IQueryable<TEntity> Like<TEntity, TKey>(this IQueryable<TEntity> query, Expression<Func<TEntity, TKey>> predicate, string text) where TEntity : class {
DbSet<TEntity> entities = query as DbSet<TEntity>;
string columnDataBase = ColumnDataBase(entities.EntityType.Model, predicate);
return entities.FromSqlRaw(query.ToQueryString() + " WHERE [" + columnDataBase + "] LIKE {0}", text);
}
}
public async Task<IEnumerable<TEntity>> LikeAsync<TKey>(Expression<Func<TEntity, TKey>> predicate, string text, CancellationToken cancellationToken) {
return await context.LikeAsync(predicate, text, cancellationToken);
}
public IQueryable<TEntity> Like<TKey>(Expression<Func<TEntity, TKey>> predicate, string text) {
return context.Like(predicate, text);
}
IQueryable<CountryEntity> result = countryRepository
.Like(k => k.Name, "%Bra[sz]il%") /*Use Sync*/
.Where(w => w.DateRegister < DateTime.Now) /*Example*/
.Take(10); /*Example*/
Or要么
IEnumerable<CountryEntity> result = await countryRepository
.LikeAsync(k => k.Name, "%Bra[sz]il%", cancellationToken); /*Use Async*/
Or要么
IQueryable<CountryEntity> result = context.Countries
.Like(k => k.Name, "%Bra[sz]il%")
.Where(w => w.Name != null); /*Example*/
Or要么
List<CountryEntity> result2 = await context.Countries
.Like(k => k.Name, "%Bra[sz]il%")
.Where(w => w.Name != null) /*Example*/
.ToListAsync(); /*Use Async*/
Or要么
IEnumerable<CountryEntity> result3 = await context.Countries
.Where(w => w.Name != null)
.LikeAsync(k => k.Name, "%Bra[sz]il%", cancellationToken); /*Use Async*/
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;
Just add to string object extention methods.只需添加到字符串对象扩展方法。
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;
}
}
usage:用法:
use namespase that contains this class;
var sPortCode = Database.DischargePorts
.Where(p => p.PortName.Contains(new string [] {"BALTIMORE"}, StringComparison.CurrentCultureIgnoreCase) )
.Single().PortCode;
@adobrzyc had this great custom LIKE
function - I just wanted to share the IEnumerable
version of it. @adobrzyc 有这个很棒的自定义LIKE
函数——我只是想分享它的IEnumerable
版本。
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;
}
}
Great custom LIKE function by @adobrzyc don't work for me in LINQPad
. @adobrzyc的出色自定义LIKE函数don't work for me in LINQPad
。
Here version which work in LINQPad
(tested on LINQPad 5 and LINQPad 6)在 LINQPad 中work in LINQPad
此处版本(在 LINQPad 5 和 LINQPad 6 上测试)
Code代码
void Main()
{
var users = from au in ApplicationUsers
select au;
users.Like(u => u.UserName, "Ada Byron").Dump();
users.Like(u => u.UserName, "%yro%").Dump();
users.Like(u => u.UserName, "% Byron").Dump();
users.Like(u => u.UserName, "Ada %").Dump();
users.Like(u => u.UserName, "%yro%").Like(u => u.UserName, "Ada %").Dump();
// => SQL =>
// DECLARE @p0 NVarChar(1000) = 'Ada %'
// DECLARE @p1 NVarChar(1000) = '%yro%'
// SELECT [t0].[UserName], ...
// FROM [ApplicationUsers] AS [t0]
// WHERE ([t0].[UserName] LIKE @p0) AND ([t0].[UserName] LIKE @p1)
}
// based on LinqEx by adobrzyc (https://stackoverflow.com/a/35636138/1351740)
public static class LinqExFork
{
private static readonly MethodInfo ContainsMethod = typeof(string).GetMethod("Contains", new[] { typeof(string) });
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 memberInfo = GetMemberInfo(property);
MemberExpression member;
if (memberInfo is PropertyInfo)
member = Expression.Property(param, memberInfo.Name);
else if (memberInfo is FieldInfo)
member = Expression.Field(param, memberInfo.Name);
else
throw new InvalidOperationException("Unable to determine propery or field info from expression.");
var startWith = value.StartsWith("%");
if (startWith)
value = value.Remove(0, 1);
var endsWith = value.EndsWith("%");
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 MemberInfo GetMemberInfo(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 member info from expression.");
var output = memberExpr.Member as MemberInfo;
if (output == null)
throw new InvalidOperationException("Specified expression is invalid. Unable to determine member info from expression.");
return output;
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.