【问题标题】:Method 'Boolean Contains..' has no supported translation to SQL方法 'Boolean Contains..' 不支持对 SQL 的转换
【发布时间】:2014-09-04 07:55:26
【问题描述】:

我的查询中有这个:

var results = (from urls in _context.Urls
               join documents in _context.Documents on urls.UrlId equals documents.DocumentId
               let words = (from words in _context.Words
                            join hits in _context.Hits on words.WordId equals hits.WordId
                            where hits.DocumentId == documents.DocumentId
                            select words.Text).AsEnumerable<string>()

                where urls.ResolvedPath.Contains(breakedQuery, KeywordParts.Url, part) ||
                      documents.Title.Contains(breakedQuery, KeywordParts.Title, part) ||
                      documents.Keywords.Contains(breakedQuery, KeywordParts.Keywords, part) ||
                      documents.Description.Contains(breakedQuery, KeywordParts.Description, part) ||
                      words.Contains(breakedQuery, KeywordParts.Content, part) ...

并包含扩展方法:

字符串

public static bool Contains(this string source, IEnumerable<string> values, KeywordParts valuePart, KeywordParts part)
    {
        if (!string.IsNullOrWhiteSpace(source))
            return source.Split(' ').AsEnumerable<string>().Contains(values, valuePart, part);
        return false;
    }

用于可枚举(主要方法)

public static bool Contains(this IEnumerable<string> source, IEnumerable<string> values, KeywordParts valuePart, KeywordParts part)
    {
        if (source != null && source.Count() > 0 &&
            values != null && values.Count() > 0 &&
            (part == KeywordParts.Anywhere || valuePart == part))
        {
            foreach (var value in values)
            {
                var has = false;
                var none = (value.StartsWith("-"));
                string term = value.Replace("-", "");

                if (none)
                    has = source.Any(q => !q.Contains(value));
                else
                    has = source.Any(q => q.Contains(values));

                if (has)
                    return has;
            }
        }
        return false;
    }

使用 Contains 方法会引发异常 NotSupportedException: Method 'Boolean Contains(String, IEnumerable`1[String], KeywordParts, KeywordParts)' 不支持 SQL 转换。

实际上我想检查每个索引文档是否至少具有指定条件之一

【问题讨论】:

    标签: c# linq-to-sql .net-4.0


    【解决方案1】:

    您不能只编写自己的方法并从查询表达式中调用它们 - 查询翻译器不知道该方法的用途。

    您可以在获取文档和单词后强制在 .NET 中执行 where 子句,可能...尽管显然这意味着从数据库中获取 所有 连接数据。这样可以吗?

    为此,您需要以下内容:

    var tmpQuery = (from urls in _context.Urls
                    join documents in _context.Documents 
                    on urls.UrlId equals documents.DocumentId
                    let words = (from words in _context.Words
                                 join hits in _context.Hits 
                                 on words.WordId equals hits.WordId
                                 where hits.DocumentId == documents.DocumentId
                                 select words.Text)
                    select new { urls, documents, words };
    
    var query = from r in tmpQuery.AsEnumerable()
                let urls = r.urls.ToList()
                let words = r.words.ToList()
                let documents = r.documents.ToList()
                where urls.ResolvedPath.Contains(breakedQuery, 
                                                 KeywordParts.Url, part) ||
                   documents.Title.Contains(breakedQuery,
                                            KeywordParts.Title, part) ||
                   documents.Keywords.Contains(breakedQuery,
                                               KeywordParts.Keywords, part) || 
                   documents.Description.Contains(breakedQuery, 
                                                  KeywordParts.Description, part) ||
                   words.Contains(breakedQuery, KeywordParts.Content, part)
                select new { urls, words, documents };
    

    【讨论】:

    • 很好,谢谢。你能给我一个方法来提高执行这个查询的速度吗?如您所知,我正在开发非常基本的网络搜索引擎,这是项目搜索部分的一部分。在我检索到结果后,我想按在选择中计算的每个比率对结果进行排序。我将在单独的问题中发布评分部分。
    【解决方案2】:

    我的理解,如果我错了,请有人纠正我,问题是当使用 Linq to SQL 的扩展方法时,扩展方法不像您在问题中的扩展方法那样作为 .NET 代码执行。

    Linq to SQL 扩展方法返回 expression trees,然后 Linq to SQL 引擎对其进行解析并生成适当的 SQL 查询以满足表达式树。

    【讨论】:

    • 是的,完全正确。在这种情况下,表达式树将引用对Contains 的调用,而 LINQ to SQL 并不知道。
    【解决方案3】:

    实现此功能的另一种方法是在实现此功能的数据库中编写一个标量 UDF。然后将该 UDF 拖到 LINQ-to-SQL 设计器上,这将使您能够通过数据上下文访问您的 UDF。然后你可以使用类似的东西:

    where _context.MyContains(documents.Title, breakedQuery,
           KeywordParts.Title, part);
    

    翻译后会调用UDF(即WHERE dbo.MyContains(...)

    【讨论】:

      【解决方案4】:

      一个有趣的事实是,在我的开发机器上运行 .NET 4.0 时出现以下错误:

      “方法 'Boolean Contains(Int32)' 不支持对 SQL 的转换。”

      但它在使用 .NET 3.5 的生产环境中运行良好。

      我猜这是两个环境之间版本的差异。但是,事实上我在开发机器上遇到了错误,但是查询在生产环境中运行,并且 LINQ 查询确实包含以下代码

      var resultParts = (
                      from l in tempDc.LineItems
                      from wo in tempDc.WorkOrders
                      where l.WorkOrderNumber == wo.WorkOrderNumber &&
                          l.OrderID == wo.OrderID &&
                          workOrderSerialNumbers.Contains(wo.SerialNumber) &&
                          l.Part.PartTypeID == (int)PartTypes.InventoryPart
                      orderby l.OrderID_WO, l.WorkOrderNumber
                      select new PickReportPartDto()
                      {...
      

      'workOrderSerialNumbers 是一个列表。

      【讨论】:

        【解决方案5】:

        如果您在 .Contains(r.SomeId) 之前获取枚举并添加到 .ToList(),这是可能的。我正在搜索此错误,最初有一个带有 .Contains(r.SomeId) 的 ICollection 会引发此异常,但是执行 .ToList() 解决了我的问题。希望这对其他人有帮助。

        注意:我相信 Linq2Sql 有一个最大的表达式树......所以一个大的列表可能会让你再次头疼。只是一个想法和需要注意的事情。

        这是 Linq2Sql 代码:

        这是生成的 SQL:

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2012-06-07
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多