代码之家  ›  专栏  ›  技术社区  ›  brien

像实体框架中的运算符?

  •  79
  • brien  · 技术社区  · 15 年前

    我们正试图在实体框架中为具有字符串字段的实体实现“like”运算符,但似乎不受支持。有没有其他人尝试过这样做?

    这个 blog post 总结我们遇到的问题。我们可以使用contains,但它只匹配最简单的like。结合使用contains、startswith、endswith和indexof可以到达那里,但是需要在标准通配符和linq到实体代码之间进行转换。

    9 回复  |  直到 6 年前
        1
  •  28
  •   Yann Duran    6 年前

    这是一篇旧文章,但对于任何寻求答案的人来说, this link 应该帮助。

    短版:

    sqlfunctions.patindex 方法-返回指定表达式中第一个出现的模式的起始位置,如果在所有有效的文本和字符数据类型上找不到该模式,则返回零。

    命名空间:system.data.objects.sqlclient 程序集:system.data.entity(在system.data.entity.dll中)

    这里面也有一些解释。 forum thread .

        2
  •  142
  •   Jon Skeet    15 年前

    我真的对ef一无所知,但在linq to sql中,通常使用字符串来表示like子句。包含:

    where entity.Name.Contains("xyz")
    

    翻译为

    WHERE Name LIKE '%xyz%'
    

    (使用) StartsWith EndsWith 其他行为。)

    我不完全确定这是否有帮助,因为我不明白你说你想说的是什么意思。 实施 喜欢。如果我完全误解了,请告诉我,我将删除此答案:)

        3
  •  32
  •   surfen    11 年前

    我也有同样的问题。

    目前,我已经使用基于 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/en-us/library/system.data.objects.sqlclient.sqlfunctions.patindex.aspx

    这样地:

    var q = EFContext.Products.Where(x =>
    SqlFunctions.PatIndex("%CD%BLUE%", x.ProductName) > 0);
    

    注意:此解决方案仅适用于SQL Server,因为它使用非标准的patindex函数。

        4
  •  14
  •   Lode Vlaeminck    7 年前

    更新:在EF6.2中有一个类似的运算符

    Where(i => DbFunctions.Like(searchstring ,like expression)
    
        5
  •  9
  •   Dmitry Pavlov    7 年前

    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 喜欢 而不是 CHARINDEX 我们看到 Contains 方法。

        6
  •  5
  •   Robert Harvey    15 年前

    文档中特别提到了它作为实体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%'
    

    http://msdn.microsoft.com/en-us/library/bb399359.aspx

        7
  •  2
  •   teamchong    10 年前

    如果您使用的是MS SQL,我已经编写了两个扩展方法来支持通配符搜索的%字符。 (需要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_uu linq_uu 0='he%llo%'、@p_u linq_u 1='hi%'、@p_u linq_2='active'

        8
  •  0
  •   th2tran    15 年前

    回复:“我们希望能在布拉赫比赛 瞎说 酒吧?酒吧?Fo*酒吧?以及其他复杂的模式。” 我实际上还没有尝试过(还没有必要尝试过),但是您尝试过使用System.Text.RegularExpressions.RegEx吗?

        9
  •  0
  •   brechtvhb    9 年前

    您可以很容易地使用真正的like链接到实体

    添加

        <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:conceptmodels/模式

    还请记住 <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