我的查询中有这个:
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转换。
实际上我想检查每个索引文档是否至少有一个指定的条件
答案 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代码:
这是结果SQL: