我想知道是否可以使用LINQ进行通配符搜索。
我看到LINQ有Contains,StartsWith,EndsWith等等。
如果我需要像%Test那样的东西,如果它有效%%,我该怎么办?
此致
答案 0 :(得分:75)
您可以使用SqlMethods.Like()。
用法示例:
var results =
from u in users
where SqlMethods.Like(u.FirstName, "%John%")
select u;
答案 1 :(得分:33)
我会使用正则表达式,因为您可能并不总是使用Linq to SQL。
像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);
}
答案 2 :(得分:14)
将System.Data.Linq.SqlClient添加到您的使用或导入列表,然后尝试:
var results= from x in data
where SqlMethods.Like(x.SearchField, “%something%like%this%”)
select x;
答案 3 :(得分:6)
对于Entity Framework Core 2.0
,有LIKE
运算符(announced in August 2017):
var query = from e in _context.Employees
where EF.Functions.Like(e.Title, "%developer%")
select e;
答案 4 :(得分:3)
查看问题
如果我需要像%Test那样的东西,如果它有效%%,我该怎么办?
然后我期待一些
LIKE '%Test if%it work%'
意味着该字符串必须包含“测试是否”和“它是否正常”,按此顺序。
这不起作用:
context.SomeTable.Where(s => s.Name.Contains("Test if%it work")).ToList();
如果我使用:
context.SomeTable.Where(s => s.Name.Contains("Test if") && s.Name.Contains("it work")).ToList();
然后我将找到包含“测试是否”和“它是否正常”的所有记录,但不是特定的顺序。
因此,使用包含,这是不可能的。但是使用 IndexOf 就是。
IndexOf将找到searchstring并返回它在字符串中的位置。可以按正确的顺序查找单词。
- 更新 -
根据我的原始答案,提供通用解决方案不是我的目标,而是另一种不依赖于sql的方法的示例。因此,原始示例仅回答文字问题是正确的。但是,如果它是通用的,答案可能会更有用,我编写了一个IQuerable扩展,允许像查询一样简单地向查询添加like语句。该扩展适用于Linq和Linq-Sql。
这将按顺序查找“测试是否”和“工作正常”的所有记录。
context.SomeTable.Like("test if%it work", "Name").ToList();
listOfString.Like("test if%it work").ToList();
扩展,允许任意数量的通配符:
/// <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;
}
由于它不需要SqlMethods,我假设您可以将它用于任何数据库,如MySql或Postgresql。但我不确定。我使用Entity Framework 6对Sql Server进行了测试。上面的语句在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))
关于性能,似乎有一些关于什么是“更好”的讨论:LIKE或CHARINDEX。从我读到的CHARINDEX看起来很受欢迎。
答案 5 :(得分:2)
.Where( column LIKE "Pattern")
答案 6 :(得分:2)
var result = (from x in db.Members
where x.IDNumber.Contains(idnumber)
&& x.InstitutionIdentifier == institution.Identifier
select x).ToList();
return result;
在内存中对Linq to SQL和Linq都有效。
答案 7 :(得分:2)
我知道这是老话题,但这是我非常简单的解决方案:
string s=Regex.Escape("pattern - escaped for sanity").Replace("%", ".*").Replace("_", ".?");
user => Regex.IsMatch(user.FullName, s, RegexOptions.CultureInvariant | RegexOptions.IgnoreCase);
在这段代码中,我使用SQL语言的常用转义字符。
如果您要使用说*
和?
,则转义字符串将相应地包含\*
和\?
,请确保包含反斜杠字符.Replace(...)
语句。%
。
当然,如果您想让您的用户能够进行RexEx搜索,请不要转义模式字符串。
搜索Regex教程以获取其他选项。
我认为通常.*
将匹配至少一个字符,而RegEx %
将匹配零个或多个字符。实际上,.+
通配符更像是.*
(贪婪),而不是{{1}}(懒惰)。
希望这有帮助。
答案 8 :(得分:1)
不确定你是说LinqToSql还是只是linq ......但你可以使用这样的正则表达式:
.Where(dto => System.Text.RegularExpressions.Regex.IsMatch(dto.CustomerName, @"Ad"));
答案 9 :(得分:1)
在包含LINQ to Objects的.Net代码中,我正在使用线程Using Regex to create a SQL's "like" like function.中的 IsSqlLikeMatch 函数的实现。
使用示例
bool ret = message.IsSqlLikeMatch(pattern);
我的帖子中有更多细节 SQL's "like" patterns to compare in .Net
答案 10 :(得分:1)
您也可以使用“包含”
var myresult = db.MyItems.Where(x=>x.MyField.Contains(mysearchstring));
答案 11 :(得分:0)
您是在谈论LINQ to objects还是LINQ to SQL?
对于LINQ to对象,你必须诉诸regular expressions我认为。
答案 12 :(得分:0)
我使用它来支持用户搜索中的通配符过滤器“ *”。 (顺序无关紧要):
if (!string.IsNullOrEmpty(SearchString))
{
List<String> containValues = new List<String>();
if (SearchString.Contains("*"))
{
String[] pieces = SearchString.Split("*");
foreach (String piece in pieces)
{
if (piece != "")
{
containValues.Add(piece);
}
}
}
if (containValues.Count > 0)
{
foreach(String thisValue in containValues)
{
Items = Items.Where(s => s.Description.Contains(thisValue));
}
}
else
{
Items = Items.Where(s => s.Description.Contains(SearchString));
}
}
答案 13 :(得分:0)
我扩展了范爱宝(Ruard van Elburg)的榜样来支持我的需求,并认为我会分享。它处理通配符,例如“ a%”(startswith(a)),“%b”(endswith(b)),“ a%b”(startswith(a)&& endswith(b))和“ a%b% c”(startwith(a),indexof(a) 我知道这真的很晚,而且我知道EFv6.2 +支持Like()方法。但是也许您像我一样,在一家拥有大型旧版应用程序的小商店中,很难简单地升级.Net和EF版本。 public static class LinqLikeExtension
{
/// <summary> Permits searching a string value with any number of wildcards. This was written
/// to handle a variety of EF wildcard queries not supported because the current version is
/// less tan EFv6.2, which has a .Like() method.
/// like in EFv6.</summary>
/// <typeparam name="T">String or an object with a string member.</typeparam>
/// <param name="query">Original query</param>
/// <param name="searchstring">The searchstring</param>
/// <param name="columnName">The name of the db column, or null if not a column.</param>
/// <returns>Query filtered by 'LIKE'.</returns>
/// <example>return iQueryableRows.Like("a", "ReferenceNumber");</example>
/// <example>return iQueryableRows.Like("a%", "ReferenceNumber");</example>
/// <example>return iQueryableRows.Like("%b", "ReferenceNumber");</example>
/// <example>return iQueryableRows.Like("a%b", "ReferenceNumber");</example>
/// <example>return iQueryableRows.Like("a%b%c", "ReferenceNumber");</example>
/// <remarks>Linq (C#) is case sensitive, but sql isn't. Use StringComparison ignorecase for Linq.
/// Keep in mind that Sql however doesn't know StringComparison, so try to determine the provider.</remarks>
/// <remarks>base author -- Ruard van Elburg from StackOverflow, modifications by dvn</remarks>
/// <seealso cref="https://stackoverflow.com/questions/1040380/wildcard-search-for-linq"/>
public static IQueryable<T> Like<T>(this IQueryable<T> query, string searchstring, string columnName = null)
{
var eParam = Expression.Parameter(typeof(T), "e");
var isLinq = (query.Provider.GetType().IsGenericType && query.Provider.GetType().GetGenericTypeDefinition() == typeof(EnumerableQuery<>));
MethodInfo IndexOf, StartsWith, EndsWith, Equals;
MethodCallExpression mceCurrent, mcePrevious;
Expression method = string.IsNullOrEmpty(columnName) ? eParam : (Expression)Expression.Property(eParam, columnName);
var likeParts = searchstring.Split(new char[] { '%' });
for (int i = 0; i < likeParts.Length; i++)
{
if (likeParts[i] == string.Empty) continue; // "%a"
if (i == 0)
{
if (likeParts.Length == 1) // "a"
{
Equals = isLinq
? Equals = typeof(string).GetMethod("Equals", new[] { typeof(string), typeof(StringComparison) })
: Equals = typeof(string).GetMethod("Equals", new[] { typeof(string) });
mceCurrent = isLinq
? Expression.Call(method, Equals, new Expression[] { Expression.Constant(likeParts[i], typeof(string)), Expression.Constant(StringComparison.OrdinalIgnoreCase) })
: Expression.Call(method, Equals, Expression.Constant(likeParts[i], typeof(string)));
}
else // "a%" or "a%b"
{
StartsWith = isLinq
? StartsWith = typeof(string).GetMethod("StartsWith", new[] { typeof(string), typeof(StringComparison) })
: StartsWith = typeof(string).GetMethod("StartsWith", new[] { typeof(string) });
mceCurrent = isLinq
? Expression.Call(method, StartsWith, new Expression[] { Expression.Constant(likeParts[i], typeof(string)), Expression.Constant(StringComparison.OrdinalIgnoreCase) })
: Expression.Call(method, StartsWith, Expression.Constant(likeParts[i], typeof(string)));
}
query = query.Where(Expression.Lambda<Func<T, bool>>(mceCurrent, eParam));
}
else if (i == likeParts.Length - 1) // "a%b" or "%b"
{
EndsWith = isLinq
? EndsWith = typeof(string).GetMethod("EndsWith", new[] { typeof(string), typeof(StringComparison) })
: EndsWith = typeof(string).GetMethod("EndsWith", new[] { typeof(string) });
mceCurrent = isLinq
? Expression.Call(method, EndsWith, new Expression[] { Expression.Constant(likeParts[i], typeof(string)), Expression.Constant(StringComparison.OrdinalIgnoreCase) })
: Expression.Call(method, EndsWith, Expression.Constant(likeParts[i], typeof(string)));
query = query.Where(Expression.Lambda<Func<T, bool>>(mceCurrent, eParam));
}
else // "a%b%c"
{
IndexOf = isLinq
? IndexOf = typeof(string).GetMethod("IndexOf", new[] { typeof(string), typeof(StringComparison) })
: IndexOf = typeof(string).GetMethod("IndexOf", new[] { typeof(string) });
mceCurrent = isLinq
? Expression.Call(method, IndexOf, new Expression[] { Expression.Constant(likeParts[i], typeof(string)), Expression.Constant(StringComparison.OrdinalIgnoreCase) })
: Expression.Call(method, IndexOf, Expression.Constant(likeParts[i], typeof(string)));
mcePrevious = isLinq
? Expression.Call(method, IndexOf, new Expression[] { Expression.Constant(likeParts[i - 1], typeof(string)), Expression.Constant(StringComparison.OrdinalIgnoreCase) })
: Expression.Call(method, IndexOf, Expression.Constant(likeParts[i - 1], typeof(string)));
query = query.Where(Expression.Lambda<Func<T, bool>>(Expression.LessThan(mcePrevious, mceCurrent), eParam));
}
}
return query;
}
}