【问题标题】:LINQ to Entities does not recognize the method 'System.String[] Split(Char[])' method,LINQ to Entities 无法识别方法 'System.String[] Split(Char[])' 方法,
【发布时间】:2014-05-29 09:16:39
【问题描述】:

我正在尝试实现一种方法,其中存储在数据库中的活动关键字(用逗号分隔)与用逗号分隔的给定字符串匹配。

public List<TblActivities> SearchByMultipleKeyword(string keywords)
{
    string[] keyword = keywords.Split(',');
    var results  = (from a in Entities.TblActivities
                    where a.Keywords.Split(',').Any(p => keyword.Contains(p))
                    select a).ToList();
    return results;
}

我收到以下错误:

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

【问题讨论】:

  • 错误表明您不能使用这些函数,因为它们不可用(这些函数和 TSQL 之间没有完成映射)更好的选择可能是使用 context.ExecuteStoreQuery 你可以自己写SQL
  • 你看过右边的相关问题了吗?粗略一瞥表明您会很快找到答案...
  • @3dd 不能再反对你了。正确的选择是实际规范化数据库,以便您可以实际使用 SQL、索引和表统计信息。否则,使用 RDBMS 有什么意义。如果您真的想这样做 CSV gubbins,请改用无模式数据库!
  • @Aron 不一定正确,我们不知道关键字列的上下文,它可能无法规范化,但我同意,如果规范化会更好

标签: c# string linq


【解决方案1】:

如错误消息所述,您无法使用实体框架执行此操作。

但是,有一些选择。

一种选择是认识到,如果关键字存储为A,B,C,D,那么x 就在那里

a.Keywords.StartsWith(x + ",") || 
a.Keywords.Contains("," + x + ",") || 
a.Keywords.EndsWith("," + x)

如果x 本身不包含,,则此方法有效。缺点是这将对表或包含Keywords 列的索引进行全面扫描。

另一个选项是规范化您的数据库。毕竟,活动和关键字之间存在一对多的关系。然后对其建模:除了Activities 表(没有关键字列)之外,还有一个KeyWords 表,其中包含两列、活动表的外键和keyword 列。这将允许您在 keyword 列上添加索引,这可以使查询超快。

更新

我重新阅读了您的问题,并注意到您没有测试关键字是否相等,而只是Contains。如果是这样,您为什么不直接执行以下操作?

a.Keywords.Contains(x)

【讨论】:

  • 如果 EF / Linq-to-Entities 支持 String.Split() 会很好。我同意选择的第一个选项。
  • 您忘记了仅存储 A 的情况。添加这个:a.Keywords.StartsWith(x) ||
  • @user_s 我建议改为a.Keywords == x ||。这解决了 A 关键字可能是较长关键字的开头的问题。
【解决方案2】:

String.Split 不受实体框架支持。这仅仅是因为 SQL 中没有等价物。

解决办法是:

  1. 在数据库中定义自定义函数 本文提出几种解决方案:http://sqlperformance.com/2012/07/t-sql-queries/split-strings
  2. 使用[EdmFunction] 属性声明此函数可由LINQ to Entities 使用,如下所述:How to call DB function from EF LINQ query?

【讨论】:

    【解决方案3】:

    是的,你可以这样做:

    public List<TblActivities> SearchByMultipleKeyword(string keywords)
    {
        string[] keywordsSeparated = keywords.Split(',');
        var results  = (from a in Entities.TblActivities
                        where keywordsSeparated.Any(keyword => a.Keywords.Contains(keyword))
                        select a).ToList();
        return results;
    }
    

    【讨论】:

    • 不知道为什么这没有被赞成 - 这是唯一正确和可信的答案。
    • 我必须同意@JohnOhara。这对我来说非常有效。我使用了这个并将结果与​​我试图在 SSMS 中实现的 SQL 脚本进行了比较。
    【解决方案4】:

    对于不涉及太多关键字和太多行的查询,您可以实施这个简单快捷的解决方案。您可以通过如下反复细化结果轻松绕过拆分功能:

     public List<TblActivities> SearchByMultipleKeyword(string keywords)
     {
         string[] keywords = pKeywords.Split(',');
    
         var results = Entities.TblActivities.AsQueryable();    
    
         foreach(string k in keywords){
    
             results  = from a in results
                        where a.Keywords.Contains(k)
                        select a;
         }
         return results.ToList();
     }
    

    【讨论】:

    • 我认为您的代码示例中有错字。它应该说 SearchByMultipleKeyword(string pKeywords) - 注意“pKeywords”而不是简单的关键字“
    【解决方案5】:

    LINQ to Entities 尝试将您的 LINQ 查询转换为 SQL。由于它不知道如何在 SQL 查询中执行String.Split,所以它失败了。

    这意味着除非你想写一个String.Split的SQL实现,你只能在LINQ to objects中做,这意味着你需要先把你所有的数据加载到内存中,然后再做where子句.一种简单的方法是使用.ToList()

    var results  = (from a in Entities.TblActivities select a).ToList(); //Results are now in memory
    results = results.Where(a =>
         a.Keywords.Split(',').Any(p => keyword.Contains(p))).ToList(); //This uses LINQ-to-objects
    

    【讨论】:

    • 如果我们谈论的是兆字节(最多),这可能会起作用,尽管它可能非常慢。如果我们说的是很多 GB,它甚至可能不起作用。
    • @KrisVandermotten 我同意。可能正确的解决方案是更改数据库或编写自定义 SQL,但其中任何一个似乎都超出了问题的范围。
    【解决方案6】:

    不确定,但您可以尝试: 由于错误似乎是在寻找一个数组,这可能会起作用。

    string[] keyword = keywords.Split(new char[] {','});
    
    var results  = (from a in Entities.TblActivities
                    where a.Keywords.Split(new char[] {','}).Any(p => keyword.Contains(p))
                    select a).ToList();
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-05-03
      • 2013-04-07
      • 2017-08-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-10-07
      相关资源
      最近更新 更多