【问题标题】:Linq SqlMethods.Like failsLinq SqlMethods.Like 失败
【发布时间】:2010-04-06 12:02:21
【问题描述】:

我正在遵循提示here,试图利用在枚举器被触发之前不会创建 sql 的语句。但是,我在下面的代码中收到以下错误。我使用的是 Linq2Entities,而不是 linq2sql。有没有办法在 Linq2entities 中做到这一点?

方法'Boolean Like(System.String, System.String)'不能在客户端使用;它仅用于转换为 SQL。

            query = db.MyTables.Where(x => astringvar.Contains(x.Field1));

            if (!String.IsNullOrEmpty(typeFilter))
            {
                if (typeFilter.Contains('*'))
                {
                    typeFilter = typeFilter.Replace('*', '%');
                    query = query.Where(x=> SqlMethods.Like(x.Type, typeFilter));
                }
                else
                {
                    query  = query.Where(x => x.Type == typeFilter);
                }
            }

注意:db 是到 sql server 的实体映射。

【问题讨论】:

    标签: .net linq-to-entities


    【解决方案1】:

    我不知道如何让 Entity Framework 使用“真正的”LIKE 运算符,但一种可能的解决方法是用 StartsWithContainsEndsWith 表达 LIKE 表达式

    例如:

    LIKE 'a%' => StartsWith("a")
    LIKE '%a' => EndsWith("a")
    LIKE '%a%' => Contains("a")
    LIKE 'a%b' => StartsWith("a") && EndsWith("b")
    LIKE 'a%b%' => StartsWith("a") && Contains("b")
    

    等等……

    请注意,它并不完全等同于在 SQL 中使用 LIKE:例如 LIKE '%abc%bcd%' 将导致 Contains("abc") && Contains("bcd")。即使原始 LIKE 条件不匹配,这也会匹配“abcd”。但在大多数情况下,它应该已经足够了。

    这是一个示例实现,使用 PredicateBuilderLinqKit 来构建基于 LIKE 模式的表达式:

    public static class ExpressionHelper
    {
        public static Expression<Func<T, bool>> StringLike<T>(Expression<Func<T, string>> selector, string pattern)
        {
            var predicate = PredicateBuilder.True<T>();
            var parts = pattern.Split('%');
            if (parts.Length == 1) // not '%' sign
            {
                predicate = predicate.And(s => selector.Compile()(s) == pattern);
            }
            else
            {
                for (int i = 0; i < parts.Length; i++)
                {
                    string p = parts[i];
                    if (p.Length > 0)
                    {
                        if (i == 0)
                        {
                            predicate = predicate.And(s => selector.Compile()(s).StartsWith(p));
                        }
                        else if (i == parts.Length - 1)
                        {
                            predicate = predicate.And(s => selector.Compile()(s).EndsWith(p));
                        }
                        else
                        {
                            predicate = predicate.And(s => selector.Compile()(s).Contains(p));
                        }
                    }
                }
            }
            return predicate;
        }
    }
    

    你可以这样使用它:

    var expr = ExpressionHelper.StringLike<YourClass>(x => x.Type, typeFilter);
    query = query.AsExpandable().Where(expr.Compile());
    

    我刚刚尝试了一个简单的 EF 模型,它似乎工作正常 :)

    【讨论】:

    • 不幸的是,我需要真正的“LIKE”,但这是一个有趣的解决方案。
    • 有趣的方法,虽然LIKE '%a%b%' =&gt; StartsWith("a") &amp;&amp; Contains("b") 不是真的,因为你一开始有太多的百分之一。 LIKE 'a%b%' 更好。
    【解决方案2】:

    您可以执行 ESQL 并执行以下操作..

         db.MyTables.Where("it.Type like '" + typeFilter + "'").ToList();
    

    【讨论】:

    • 这不能在我的系统上编译(即使添加了缺失的 +)。我在 vs2008,.net 3.5 sp1
    • 没关系,它必须专门直接上表,而不是以后的ienumerable。谢谢。
    • 现在它只是得到 'FieldName' 无法在当前范围或上下文中解析。
    【解决方案3】:

    SqlMethods class 旨在与 LINQ-to-SQL 一起使用。当您使用其中的方法时(公共文档告诉您不要这样做,它不是供公众使用的),LINQ-to-Entities 的IQueryable 提供程序不知道如何处理它或如何翻译它。

    如果您在过滤器的开头或结尾有一个通配符,那么您可以在String 类上使用StartsWithEndsWith 方法,LINQ-to-Entities 将支持这一点。

    但是,在这种情况下,通配符的数量是可变的,因此您必须下拉到 ESQL 级别并从中构建查询,如 Nix's answer 中所示。

    【讨论】:

      【解决方案4】:

      您可以在链接到实体中使用真实的喜欢

      添加

          <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

      还要记住&lt;schema namespace="" /&gt; 属性中的命名空间

      然后在上面的命名空间中添加一个扩展类:

      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

      【讨论】:

        【解决方案5】:

        我发布了my solution here,以防万一它也是:

        2019 年更新

        对于 Entity Framework 6.2,您可以使用 DBFunctions

        例如:

        try
        {
            using (var db = new YOUREntities())
            {
                var data = db.LenderProgram.Where(i => DbFunctions.Like(i.LenderProgramCode, "OTO%"))
                    .ToList();
                return data;
            }
        }
        catch (Exception e)
        {
            e.HandleException();
        }
        

        【讨论】:

          猜你喜欢
          • 2017-03-31
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2022-01-03
          • 2023-03-06
          • 1970-01-01
          相关资源
          最近更新 更多