C# Like运算符或在LINQ to实体中使用通配符
我使用的是LINQ2实体。 问题如下:C# Like运算符或在LINQ to实体中使用通配符,c#,linq,linq-to-entities,C#,Linq,Linq To Entities,我使用的是LINQ2实体。 问题如下: string str = '%test%.doc%' .Contains(str) // converts this into LIKE '%~%test~%.doc~%%' 预期转换:如“%test%.doc%” 如果是Linq2SQL,我可以使用SqlMethods,就像有人在我前面的问题中回答的那样。但现在由于我使用的是L2E而不是L2S,我需要其他解决方案。您可以尝试使用,作者介绍了如何使用LINQ to实体中的通配符构建LIKE语句 编辑:由
string str = '%test%.doc%'
.Contains(str) // converts this into LIKE '%~%test~%.doc~%%'
预期转换:如“%test%.doc%”
如果是Linq2SQL,我可以使用SqlMethods,就像有人在我前面的问题中回答的那样。但现在由于我使用的是L2E而不是L2S,我需要其他解决方案。您可以尝试使用,作者介绍了如何使用LINQ to实体中的通配符构建LIKE语句
编辑:由于原来的链接现在已失效,下面是原来的扩展类(根据)和用法示例
扩展名:
public static class LinqHelper
{
//Support IQueryable (Linq to Entities)
public static IQueryable<TSource> WhereLike<TSource>(this IQueryable<TSource> source, Expression<Func<TSource, string>> valueSelector, string value, char wildcard)
{
return source.Where(BuildLikeExpression(valueSelector, value, wildcard));
}
//Support IEnumerable (Linq to objects)
public static IEnumerable<TSource> WhereLike<TSource>(this IEnumerable<TSource> sequence, Func<TSource, string> expression, string value, char wildcard)
{
var regEx = WildcardToRegex(value, wildcard);
//Prevent multiple enumeration:
var arraySequence = sequence as TSource[] ?? sequence.ToArray();
try
{
return arraySequence.Where(item => Regex.IsMatch(expression(item), regEx));
}
catch (ArgumentNullException)
{
return arraySequence;
}
}
//Used for the IEnumerable support
private static string WildcardToRegex(string value, char wildcard)
{
return "(?i:^" + Regex.Escape(value).Replace("\\" + wildcard, "." + wildcard) + "$)";
}
//Used for the IQueryable support
private static Expression<Func<TElement, bool>> BuildLikeExpression<TElement>(Expression<Func<TElement, string>> valueSelector, string value, char wildcard)
{
if (valueSelector == null) throw new ArgumentNullException("valueSelector");
var method = GetLikeMethod(value, wildcard);
value = value.Trim(wildcard);
var body = Expression.Call(valueSelector.Body, method, Expression.Constant(value));
var parameter = valueSelector.Parameters.Single();
return Expression.Lambda<Func<TElement, bool>>(body, parameter);
}
private static MethodInfo GetLikeMethod(string value, char wildcard)
{
var methodName = "Equals";
var textLength = value.Length;
value = value.TrimEnd(wildcard);
if (textLength > value.Length)
{
methodName = "StartsWith";
textLength = value.Length;
}
value = value.TrimStart(wildcard);
if (textLength > value.Length)
{
methodName = (methodName == "StartsWith") ? "Contains" : "EndsWith";
}
var stringType = typeof(string);
return stringType.GetMethod(methodName, new[] { stringType });
}
}
string strEmailToFind = "%@yahoo.com"
IQueryable<User> myUsers = entities.Users.WhereLike(u => u.EmailAddress, strEmailToFind, '%');
公共静态类LinqHelper
{
//支持IQueryable(Linq到实体)
公共静态IQueryable WhereLike(此IQueryable源、表达式值选择器、字符串值、字符通配符)
{
返回source.Where(BuildLikeExpression(valueSelector,value,通配符));
}
//支持IEnumerable(Linq到对象)
公共静态IEnumerable WhereLike(此IEnumerable序列、Func表达式、字符串值、字符通配符)
{
var regEx=通配符toregex(值,通配符);
//防止多重枚举:
var arraySequence=作为TSource[]的序列?sequence.ToArray();
尝试
{
返回arraySequence.Where(item=>Regex.IsMatch(表达式(item),Regex));
}
捕获(异常)
{
返回序列;
}
}
//用于IEnumerable支持
私有静态字符串通配符toregex(字符串值,字符通配符)
{
返回“(?i:^”+Regex.Escape(value).Replace(“\\”+通配符,“.”+通配符)+“$”;
}
//用于可更换支架
私有静态表达式BuildLikeExpression(表达式值选择器、字符串值、字符通配符)
{
如果(valueSelector==null)抛出新的ArgumentNullException(“valueSelector”);
var方法=GetLikeMethod(值,通配符);
value=value.Trim(通配符);
var body=Expression.Call(valueSelector.body,方法,Expression.Constant(value));
var parameter=valueSelector.Parameters.Single();
返回表达式.Lambda(主体,参数);
}
私有静态MethodInfo GetLikeMethod(字符串值,字符通配符)
{
var methodName=“等于”;
var textLength=value.Length;
value=value.TrimEnd(通配符);
如果(textLength>value.Length)
{
methodName=“StartsWith”;
textLength=value.Length;
}
value=value.TrimStart(通配符);
如果(textLength>value.Length)
{
methodName=(methodName=“StartWith”)?“包含”:“EndsWith”;
}
var stringType=typeof(字符串);
返回stringType.GetMethod(methodName,new[]{stringType});
}
}
用法示例:
public static class LinqHelper
{
//Support IQueryable (Linq to Entities)
public static IQueryable<TSource> WhereLike<TSource>(this IQueryable<TSource> source, Expression<Func<TSource, string>> valueSelector, string value, char wildcard)
{
return source.Where(BuildLikeExpression(valueSelector, value, wildcard));
}
//Support IEnumerable (Linq to objects)
public static IEnumerable<TSource> WhereLike<TSource>(this IEnumerable<TSource> sequence, Func<TSource, string> expression, string value, char wildcard)
{
var regEx = WildcardToRegex(value, wildcard);
//Prevent multiple enumeration:
var arraySequence = sequence as TSource[] ?? sequence.ToArray();
try
{
return arraySequence.Where(item => Regex.IsMatch(expression(item), regEx));
}
catch (ArgumentNullException)
{
return arraySequence;
}
}
//Used for the IEnumerable support
private static string WildcardToRegex(string value, char wildcard)
{
return "(?i:^" + Regex.Escape(value).Replace("\\" + wildcard, "." + wildcard) + "$)";
}
//Used for the IQueryable support
private static Expression<Func<TElement, bool>> BuildLikeExpression<TElement>(Expression<Func<TElement, string>> valueSelector, string value, char wildcard)
{
if (valueSelector == null) throw new ArgumentNullException("valueSelector");
var method = GetLikeMethod(value, wildcard);
value = value.Trim(wildcard);
var body = Expression.Call(valueSelector.Body, method, Expression.Constant(value));
var parameter = valueSelector.Parameters.Single();
return Expression.Lambda<Func<TElement, bool>>(body, parameter);
}
private static MethodInfo GetLikeMethod(string value, char wildcard)
{
var methodName = "Equals";
var textLength = value.Length;
value = value.TrimEnd(wildcard);
if (textLength > value.Length)
{
methodName = "StartsWith";
textLength = value.Length;
}
value = value.TrimStart(wildcard);
if (textLength > value.Length)
{
methodName = (methodName == "StartsWith") ? "Contains" : "EndsWith";
}
var stringType = typeof(string);
return stringType.GetMethod(methodName, new[] { stringType });
}
}
string strEmailToFind = "%@yahoo.com"
IQueryable<User> myUsers = entities.Users.WhereLike(u => u.EmailAddress, strEmailToFind, '%');
string strEmailToFind=“%@yahoo.com”
IQueryable myUsers=entities.Users.WhereLike(u=>u.EmailAddress,strEmailToFind,“%”);
或者,如果您希望用户更习惯于Windows资源管理器样式的通配符:
string strEmailToFind = "*@yahoo.com"
IQueryable<User> myUsers = entities.Users.WhereLike(u => u.EmailAddress, strEmailToFind, '*');
string strEmailToFind=“*@yahoo.com”
IQueryable myUsers=entities.Users.WhereLike(u=>u.EmailAddress,strEmailToFind,“*”);
使用正则表达式
下面将打印出当前目录中与test.doc*匹配的所有文件(dos通配符样式-我相信这就是您所要求的)
拆线
var str = "%test%.doc%";
var arr = str.Split(new[]{'%'} ,StringSplitOptions.RemoveEmptyEntries);
var q = tblUsers.Select (u => u);
foreach (var item in arr)
{
var localItem = item;
q = q.Where (x => x.userName.Contains(localItem));
}
根据Magnus的正确答案,下面是一个可以重复使用的扩展方法,正如我在项目中需要的那样
public static class LinqExtensions
{
public static Expression<Func<T, bool>> WildCardWhere<T>(this Expression<Func<T, bool>> source, Expression<Func<T, string>> selector, string terms, char separator)
{
if (terms == null || selector == null)
return source;
foreach (string term in terms.Split(new[] { separator }, StringSplitOptions.RemoveEmptyEntries))
{
string current = term;
source = source.And(
Expression.Lambda<Func<T, bool>>(
Expression.Call(selector.Body, "Contains", null, Expression.Constant(current)),
selector.Parameters[0]
)
);
}
return source;
}
}
公共静态类LinqExtensions
{
公共静态表达式通配符where(此表达式源、表达式选择器、字符串术语、字符分隔符)
{
如果(术语==null | |选择器==null)
返回源;
foreach(terms.Split中的字符串项(新[]{separator},StringSplitOptions.RemoveEmptyEntries))
{
字符串电流=术语;
来源=来源。和(
Lambda(
Expression.Call(selector.Body,“Contains”,null,Expression.Constant(current)),
选择器。参数[0]
)
);
}
返回源;
}
}
用法:
var terms = "%test%.doc%";
Expression<Func<Doc, bool>> whereClause = d => d;
whereClause = whereClause.WildCardWhere(d => d.docName, terms, '%');
whereClause = whereClause.WildCardWhere(d => d.someOtherProperty, "another%string%of%terms", '%');
var result = ListOfDocs.Where(whereClause).ToList();
var terms=“%test%.doc%”;
表达式whereClause=d=>d;
whereClause=whereClause.WildCardWhere(d=>d.docName,术语“%”);
whereClause=whereClause.WildCardWhere(d=>d.someOtherProperty,“另一个%string%的%terms”,“%”);
var result=ListOfDocs.Where(Where子句).ToList();
该扩展在上使用谓词生成器。结果sql对该表进行单表扫描,不管其中有多少项。Jo Vdb有一个扩展,如果您想改为使用iQueryable的扩展,您可以从它开始。SQL方法PATINDEX提供了与LIKE相同的功能。因此,您可以使用以下方法:
所以我也在尝试同样的事情——尝试配对一个列表,返回所有匹配搜索词的候选人。我希望这样,如果用户键入“Arizona”,它将返回所有内容,而不管该案例是否包含Arizona。此外,如果用户键入“Arizona Cha”,它将返回“Arizona License Change”之类的项目。以下方面发挥了作用:
private List<Certification> GetCertListBySearchString()
{
string[] searchTerms = SearchString.Split(' ');
List<Certification> allCerts = _context.Certifications.ToList();
allCerts = searchTerms.Aggregate(allCerts, (current, thisSearchString) => (from ac in current
where ac.Name.ToUpper().Contains(thisSearchString.ToUpper())
select ac).ToList());
return allCerts;
}
private List GetCertListBySearchString()
{
string[]searchTerms=SearchString.Split(“”);
列出所有证书=_context.Certifications.ToList();
allCerts=searchTerms.Aggregate(allCerts,(当前,thisSearchString)=>(来自当前ac)
其中ac.Name.ToUpper()包含(thisSearchString.ToUpper())
选择ac.ToList());
返回所有证书;
}
我在前面看到过,它没有一个可以使用的示例,只有一个示例:entities.Table.WhereLike(el=>el.position,position,“%”)。所以你应该设置w