方法'Boolean Contains ..'没有支持的SQL转换

时间:2010-07-18 07:05:03

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

我的查询中有这个:

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:方法'Boolean Contains(String,IEnumerable`1 [String],KeywordParts,KeywordParts)'没有支持的SQL转换。

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

5 个答案:

答案 0 :(得分:3)

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

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

要做到这一点,你需要这样的东西:

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 };

答案 1 :(得分:3)

我的理解和有人请纠正我,如果我错了,问题是当使用Linq to SQL的扩展方法时,扩展方法不像.NET问题一样执行,就像你在问题中使用的扩展方法一样。

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

答案 2 :(得分:3)

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

这样的东西
where _context.MyContains(documents.Title, breakedQuery,
       KeywordParts.Title, part);

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

答案 3 :(得分:1)

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

“方法”布尔包含(Int32)'没有支持的SQL转换。“

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

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

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是List。

答案 4 :(得分:0)

如果您使用枚举并在.Contains(r.SomeId)之前添加 .ToList(),则可以执行此操作。我正在搜索这个错误,最初有一个带有.Contains(r.SomeId)的ICollection,它会抛出这个异常,但是做一个.ToList()解决了我的问题。希望这有助于其他人。

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

这是Linq2Sql代码:

enter image description here

这是结果SQL: enter image description here