【问题标题】:How to use SQL 'LIKE' with LINQ to Entities? [duplicate]如何将 SQL 'LIKE' 与 LINQ to Entities 一起使用? [复制]
【发布时间】:2010-06-22 18:04:32
【问题描述】:

我有一个文本框,允许用户指定搜索字符串,包括通配符,例如:

Joh*
*Johnson
*mit*
*ack*on

在使用 LINQ to Entities 之前,我有一个将字符串作为参数的存储过程:

SELECT * FROM Table WHERE Name LIKE @searchTerm

然后我会在传入之前执行 String.Replace('*', '%')。

现在使用 LINQ to Entities 我正在尝试完成同样的事情。我知道有 StartsWith、EndsWith 和 Contains 支持,但它不会以我需要的方式支持它。

我阅读了“SqlMethods.Like”并尝试了这个:

var people = from t in entities.People
             where SqlMethods.Like(t.Name, searchTerm)
             select new { t.Name };

但是我得到以下异常:

LINQ to Entities does not recognize the method 'Boolean Like(System.String, 
System.String)' method, and this method cannot be translated into a store 
expression.

如何使用 LINQ to Entities 获得相同的功能?

【问题讨论】:

    标签: c# sql linq-to-entities


    【解决方案1】:

    http://social.msdn.microsoft.com/Forums/en-US/adodotnetentityframework/thread/6529a35b-6629-44fb-8ea4-3a44d232d6b9/

    var people = entities.People.Where("it.Name LIKE @searchTerm", new ObjectParameter("searchTerm", searchTerm));
    

    【讨论】:

    • var people = entities.People.Where("it.Name LIKE '%' + @searchTerm + '%'", new ObjectParameter("searchTerm", searchTerm));
    • @EvgeniNabokov 仅当百分比符号尚未包含在searchTerm 中时才需要。
    • 收到错误“采用 2 个参数的方法没有重载”。任何想法为什么?
    • 如果您不想使用通用查询,可以在这里查看我的答案:stackoverflow.com/a/29298128/448355
    【解决方案2】:

    如何让它无缝工作:

    在您的 EDMX 模型中,添加:

        <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:ConceptualModels> <Schema Namespace="Your.Namespace"...

    然后,在代码中的任意位置添加此扩展方法:

        //prior to EF 6 [System.Data.Objects.DataClasses.EdmFunction("Your.Namespace", "String_Like")]
    
        //With EF 6
        [System.Data.Entity.DbFunction("Your.Namespace", "String_Like")]
        public static bool Like(this string input, string pattern)
        {
            /* Turn "off" all regular expression related syntax in
             * the pattern string. */
            pattern = Regex.Escape(pattern);
    
            /* Replace the SQL LIKE wildcard metacharacters with the
             * equivalent regular expression metacharacters. */
            pattern = pattern.Replace("%", ".*?").Replace("_", ".");
    
            /* The previous call to Regex.Escape actually turned off
             * too many metacharacters, i.e. those which are recognized by
             * both the regular expression engine and the SQL LIKE
             * statement ([...] and [^...]). Those metacharacters have
             * to be manually unescaped here. */
            pattern = pattern.Replace(@"\[", "[").Replace(@"\]", "]").Replace(@"\^", "^");
    
            return Regex.IsMatch(input, pattern, RegexOptions.IgnoreCase);
        }
    

    你有它。

    现在你可以这样做了:

    (from e in Entities
     where e.Name like '%dfghj%'
     select e)
    

    string [] test = {"Sydney", "Melbourne", "adelaide", "ryde"};
    
    test.Where(t=> t.Like("%yd%e%")).Dump();
    

    【讨论】:

    • 无法将类型“...SearcherHelper”的指定方法“Boolean Like(System.String, System.String)”转换为 LINQ to Entities 存储表达式。 :(
    • 我不明白这是如何工作的,因为在我的情况下,应用程序没有通过扩展方法运行......关于功能的任何详细描述??
    • EDMX 行(上图)将使其与 LINQ to Entities 一起使用。对于非 LINQ to 实体,将调用该方法
    • LINQ 方法不起作用,我不知道为什么。你能帮助我吗? Edmx 线路还可以,扩展还可以,现在我不知道我还能做什么才能拥有from ... where ... like
    • 在 EF6 中不再支持,因为函数必须是可组合的。但是composable function不能定义commandtext。
    【解决方案3】:

    嗯,你的选择是:

    • 使用Contains。我知道你不喜欢它,但它可能会起作用。
    • SqlFunctions 中选择一个函数。它们都在 L2E 中受支持。
    • Map your own function
    • +1 给 @Yury 以获取 ESQL。

    【讨论】:

    • 我不“不喜欢”包含。它没有按预期工作,请参阅下面我对 Mike M 的回复。SqlFunctions 中没有任何内容包含 LIKE 子句。映射你自己的功能是显而易见的,而且本质上是我在做的事情,但似乎这是一个如此简单的问题,它会被原生支持。
    • ContainsStartsWithEndsWith 之间,您可以选择所需的通配符。我相信这涵盖了您的所有情况。
    • 是的,我会使用 Contains、StartsWith 和 EndsWith - LIKE 的那些 SQL 方法太不稳定
    • @CraigStuntz SqlFunctions 链接已损坏
    • @BrianWebster 链接已更新
    【解决方案4】:

    你可以这样做:

    using System.Data.Entity;  // EntityFramework.dll v4.3
    var queryResult=db.Accounts.AsQueryable().Where(x => x.Name.Contains(queryKey));
    

    因为 Linq to Entity 无法将方法 Contains() 转换为 SQL,但 Linq to SQL 可以做到这一点。我试图找到一种可以进行强制转换的方法,最后是AsQueryable(),也是一个通用版本AsQueryable&lt;T&gt;()。我发现我可以用这种方式来做到这一点,但我不知道它有什么副作用,也许它会失去Entity 的一些功能。

    【讨论】:

      【解决方案5】:

      解决方案是使用SQLFunctions.PatIndex

      var result = from c in items
                   where SqlFunctions.PatIndex(searchstring.ToLower(), c.fieldtoSearch) > 0
                   select c;
      

      其中 'searchstring' 是要搜索的模式 'fieldtoSearch' 是要搜索的字段

      Patindex() 支持使用字符串模式搜索进行搜索。搜索不区分大小写。

      【讨论】:

      • 好简单的解决方案。
      【解决方案6】:

      您可以像这样使用 LINQ 执行所有这些语句

      string _search = "johnson";
      // joh* OR joh%
      items.Where(i => i.Name.StartsWith(_search, StringComparison.OrdinalIgnoreCase));
      // *son OR %son
      items.Where(i => i.Name.EndsWith(_search, StringComparison.OrdinalIgnoreCase));
      // *hns* OR %hns%
      items.Where(i => i.Name.ToLower().Contains(_search));
      

      【讨论】:

        【解决方案7】:

        现在,EF 支持“LIKE”用法,您可以使用所有 sql 通配符。看看这个。

        var people = from t in entities.People
                     select new { t.Name };
        people = people.Where(x => DbFunctions.Like(x.Name, searchTerm));
        

        【讨论】:

          【解决方案8】:
          var people = from t in entities.People
                           where t.Name.ToLower().Contains(searchTerm.ToLower())
                           select new { t.Name };
          

          编辑-我可能正在混合语法。我通常使用扩展方法;但是 contains 会起作用。

          【讨论】:

          • 除非包含将自动将整个搜索词包含在通配符中。如果用户想要所有名字以“Mar”开头的人 Mar* Returned Mary Marissa Omar Jamaraquoui(名称已更改以保护无辜者)
          • 更奇怪的是它还添加了一个'~'。对于空白搜索词,searchTerm 为“%”。当它查询数据库时,Contains 将其变成:@p__linq__2=N'%~%%'
          • ~ 可能被用作转义字符,以表明它正在寻找其中包含文字“%”的字符串。如果您要使用 Contains(处理通配符),那么您不能同时尝试处理通配符。
          • 因为我还没有真正使用过 LINQ to SQL...在提出 SQL 时知道底层数据库是否区分大小写是否足够聪明?这更适用于 StartsWith,但 .ToLower 可能会终止索引的使用。
          • @Tom - 你知道,我什至不确定。这是一个非常好的问题,我今晚可能需要玩一些游戏......
          【解决方案9】:

          过滤时不需要使用百分号。例如;

          如果我想检查 ItemName 不包含 '-' 我会这样做

          !Item.ItemName.Contains("-")

          在 SQL 中它将转换为 NOT LIKE '%-%'

          【讨论】:

            【解决方案10】:

            我们使用 Database First 和 EntityFramework。

            “映射您自己的功能”。方法与 nuget EntityFramework.CodeFirstStoreFunctions 一起为我们工作。

            1 步骤:在数据库中创建一个函数,如下所示:

            CREATE FUNCTION [dbo].[StringLike]
            (
                  @a nvarchar(4000),
                  @b nvarchar(4000)
            )
            RETURNS bit
            AS
            BEGIN
                RETURN 
                (SELECT CASE
                        WHEN (SELECT 1 WHERE @a LIKE @b) = 1 THEN 1
                        ELSE 0
                        END)  
            END
            

            第二步:安装nuget EntityFramework.CodeFirstStoreFunctions

            3 步:在您的代码中创建一个方法,如下所示(我在 DbContext 类中创建我的方法):

            [DbFunction("CodeFirstDatabaseSchema", "StringLike")]
            public static bool Like(string input, string pattern)
            {
                throw new NotSupportedException("Direct calls are not supported.");
            }
            

            4 步:初始化 EntityFramework.CodeFirstStoreFunctions。

            protected override void OnModelCreating(DbModelBuilder modelBuilder)
            {
                modelBuilder.Conventions.Add(new FunctionsConvention("dbo", this.GetType()));
            }
            

            5 步:现在您可以在 linq 查询中使用此方法。

            【讨论】:

              【解决方案11】:

              通过以下方法很容易实现

              var people = from t in entities.People
                           where t.Name.Contains(searchTerm)
                           select new { t.Name };
              

              使用以下规范实现通配符

              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")
              

              【讨论】:

                猜你喜欢
                • 2010-09-21
                • 1970-01-01
                • 2010-10-22
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                相关资源
                最近更新 更多