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

我在我的查询中有这个:

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() 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 values, KeywordParts valuePart, KeywordParts part) { if (!string.IsNullOrWhiteSpace(source)) return source.Split(' ').AsEnumerable().Contains(values, valuePart, part); return false; } 

对于可枚举(主要方法)

 public static bool Contains(this IEnumerable source, IEnumerable 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方法抛出exceptionNotSupportedException:方法’Boolean Contains(String,IEnumerable`1 [String],KeywordParts,KeywordParts)’没有支持的SQL转换。

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

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

您可以在获取文档和单词后强制在.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 }; 

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

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

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

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

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

一个有趣的事实是,在我的开发机器上运行.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。

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

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

这是Linq2Sql代码:

在此处输入图像描述

这是结果SQL: 在此处输入图像描述