我们正在尝试在Entity Framework中为具有字符串字段的实体实现“ LIKE”运算符,但似乎不支持该运算符。有没有其他人试图做这样的事情?
这篇博客文章总结了我们遇到的问题。我们可以使用contains,但是只匹配LIKE最简单的情况。包含,startswith,endswith和indexof的组合可以使我们到达那里,但是需要在标准通配符和Linq to Entities代码之间进行转换。
Answers:
我真的对EF一无所知,但是在LINQ to SQL中,您通常使用String来表达LIKE子句。
where entity.Name.Contains("xyz")
转换为
WHERE Name LIKE '%xyz%'
(用于StartsWith
和EndsWith
其他行为。)
我不确定是否有帮助,因为当您说要实施 LIKE 时,我不明白您的意思。如果我完全误解了,请告诉我,我将删除此答案:)
我有同样的问题。
目前,我已经基于http://www.codeproject.com/Articles/11556/Converting-Wildcards-to-Regexes?msg=1423024#xx1423024xx进行了客户端的通配符/正则表达式过滤,该方法很简单并且可以像预期。
我发现了关于该主题的另一讨论:http : //forums.asp.net/t/1654093.aspx/2/10
如果您使用Entity Framework> = 4.0,则此帖子很有希望:
使用SqlFunctions.PatIndex:
http://msdn.microsoft.com/zh-cn/library/system.data.objects.sqlclient.sqlfunctions.patindex.aspx
像这样:
var q = EFContext.Products.Where(x => SqlFunctions.PatIndex("%CD%BLUE%", x.ProductName) > 0);
注意:此解决方案仅适用于SQL Server,因为它使用了非标准的PATINDEX函数。
更新:在EF 6.2中有一个like运算符
Where(obj => DbFunctions.Like(obj.Column , "%expression%")
Where(obj => DbFunctions.Like(obj.Column , "%expression%")
吗?
在中LIKE
添加了运算符Entity Framework Core 2.0
:
var query = from e in _context.Employees
where EF.Functions.Like(e.Title, "%developer%")
select e;
... where e.Title.Contains("developer") ...
与之相比,它实际上是翻译成的,SQL
LIKE
而不是CHARINDEX
我们看到的Contains
方法。
在文档中作为实体SQL的一部分特别提到了它。您收到错误消息了吗?
// LIKE and ESCAPE
// If an AdventureWorksEntities.Product contained a Name
// with the value 'Down_Tube', the following query would find that
// value.
Select value P.Name FROM AdventureWorksEntities.Product
as P where P.Name LIKE 'DownA_%' ESCAPE 'A'
// LIKE
Select value P.Name FROM AdventureWorksEntities.Product
as P where P.Name like 'BB%'
如果您使用的是MS Sql,则我编写了2种扩展方法来支持%字符进行通配符搜索。(LinqKit是必需的)
public static class ExpressionExtension
{
public static Expression<Func<T, bool>> Like<T>(Expression<Func<T, string>> expr, string likeValue)
{
var paramExpr = expr.Parameters.First();
var memExpr = expr.Body;
if (likeValue == null || likeValue.Contains('%') != true)
{
Expression<Func<string>> valExpr = () => likeValue;
var eqExpr = Expression.Equal(memExpr, valExpr.Body);
return Expression.Lambda<Func<T, bool>>(eqExpr, paramExpr);
}
if (likeValue.Replace("%", string.Empty).Length == 0)
{
return PredicateBuilder.True<T>();
}
likeValue = Regex.Replace(likeValue, "%+", "%");
if (likeValue.Length > 2 && likeValue.Substring(1, likeValue.Length - 2).Contains('%'))
{
likeValue = likeValue.Replace("[", "[[]").Replace("_", "[_]");
Expression<Func<string>> valExpr = () => likeValue;
var patExpr = Expression.Call(typeof(SqlFunctions).GetMethod("PatIndex",
new[] { typeof(string), typeof(string) }), valExpr.Body, memExpr);
var neExpr = Expression.NotEqual(patExpr, Expression.Convert(Expression.Constant(0), typeof(int?)));
return Expression.Lambda<Func<T, bool>>(neExpr, paramExpr);
}
if (likeValue.StartsWith("%"))
{
if (likeValue.EndsWith("%") == true)
{
likeValue = likeValue.Substring(1, likeValue.Length - 2);
Expression<Func<string>> valExpr = () => likeValue;
var containsExpr = Expression.Call(memExpr, typeof(String).GetMethod("Contains",
new[] { typeof(string) }), valExpr.Body);
return Expression.Lambda<Func<T, bool>>(containsExpr, paramExpr);
}
else
{
likeValue = likeValue.Substring(1);
Expression<Func<string>> valExpr = () => likeValue;
var endsExpr = Expression.Call(memExpr, typeof(String).GetMethod("EndsWith",
new[] { typeof(string) }), valExpr.Body);
return Expression.Lambda<Func<T, bool>>(endsExpr, paramExpr);
}
}
else
{
likeValue = likeValue.Remove(likeValue.Length - 1);
Expression<Func<string>> valExpr = () => likeValue;
var startsExpr = Expression.Call(memExpr, typeof(String).GetMethod("StartsWith",
new[] { typeof(string) }), valExpr.Body);
return Expression.Lambda<Func<T, bool>>(startsExpr, paramExpr);
}
}
public static Expression<Func<T, bool>> AndLike<T>(this Expression<Func<T, bool>> predicate, Expression<Func<T, string>> expr, string likeValue)
{
var andPredicate = Like(expr, likeValue);
if (andPredicate != null)
{
predicate = predicate.And(andPredicate.Expand());
}
return predicate;
}
public static Expression<Func<T, bool>> OrLike<T>(this Expression<Func<T, bool>> predicate, Expression<Func<T, string>> expr, string likeValue)
{
var orPredicate = Like(expr, likeValue);
if (orPredicate != null)
{
predicate = predicate.Or(orPredicate.Expand());
}
return predicate;
}
}
用法
var orPredicate = PredicateBuilder.False<People>();
orPredicate = orPredicate.OrLike(per => per.Name, "He%llo%");
orPredicate = orPredicate.OrLike(per => per.Name, "%Hi%");
var predicate = PredicateBuilder.True<People>();
predicate = predicate.And(orPredicate.Expand());
predicate = predicate.AndLike(per => per.Status, "%Active");
var list = dbContext.Set<People>().Where(predicate.Expand()).ToList();
在ef6中,它应该转换为
....
from People per
where (
patindex(@p__linq__0, per.Name) <> 0
or per.Name like @p__linq__1 escape '~'
) and per.Status like @p__linq__2 escape '~'
',@ p__linq__0 ='%He%llo%',@ p__linq__1 ='%Hi%',@ p__linq_2 ='%Active'
对于EfCore,这是构建LIKE表达式的示例
protected override Expression<Func<YourEntiry, bool>> BuildLikeExpression(string searchText)
{
var likeSearch = $"%{searchText}%";
return t => EF.Functions.Like(t.Code, likeSearch)
|| EF.Functions.Like(t.FirstName, likeSearch)
|| EF.Functions.Like(t.LastName, likeSearch);
}
//Calling method
var query = dbContext.Set<YourEntity>().Where(BuildLikeExpression("Text"));
您可以轻松地在链接到实体中使用真实像
加
<Function Name="String_Like" ReturnType="Edm.Boolean">
<Parameter Name="searchingIn" Type="Edm.String" />
<Parameter Name="lookingFor" Type="Edm.String" />
<DefiningExpression>
searchingIn LIKE lookingFor
</DefiningExpression>
</Function>
在此标记中添加到您的EDMX:
edmx:Edmx / edmx:Runtime / edmx:ConceptualModels / Schema
还请记住 <schema namespace="" />
属性中
然后在上述名称空间中添加扩展类:
public static class Extensions
{
[EdmFunction("DocTrails3.Net.Database.Models", "String_Like")]
public static Boolean Like(this String searchingIn, String lookingFor)
{
throw new Exception("Not implemented");
}
}
现在,此扩展方法将映射到EDMX函数。
此处提供更多信息:http : //jendaperl.blogspot.be/2011/02/like-in-linq-to-entities.html