所以说你有一张关键词表。为简单起见,我们可以说它有2个字段,一个Id整数,Keyword varchar(100)。查询包含多个关键字。例如,查询“快速棕色狐狸”。要求是我们将采取所选Id包含至少一次出现所有三个关键字的任何记录。而且,它可以是使用StartsWith的部分匹配。我可以使用PredicateBuilder来构建最终需要的多个OR子句,但也要过滤这些记录,我需要在同一个表上为每个关键字执行JOIN。我应该注意,Id字段不是唯一的,可以有多个条目。
SQL看起来或多或少都是这样或应该
select k1.Id
from Keywords k1
inner join Keywords k2 on k1.Id = k2.Id
inner join Keywords k3 on k2.Id = k3.Id
where k1.Keyword like @k1
and k2.Keyword like @k2
and k3.Keyword like @k3
我到目前为止的LINQ将是
var predicate = PredicateBuilder.False<Keyword>();
foreach (string term in searchTerms)
{
string temp = term;
predicate = predicate.Or(p => p.Keyword.StartsWith(temp));
}
var keys = Keywords.AsExpandable().Where(predicate).ToList();
这将产生或多或少的SQL:
SELECT
[Extent1].[Id] AS [Id]
FROM [dbo].[Keywords] AS [Extent1]
WHERE ([Extent1].[Keyword] LIKE @p__linq__1 ESCAPE '~') OR ([Extent1].[Keyword] LIKE @p__linq__2 ESCAPE '~') OR ([Extent1].[Keyword] LIKE @p__linq__3 ESCAPE '~')
为了使用这个结果,我必须做一个DistinctBy然后JOIN回到我的结果。这可能会产生巨大的内存需求,我正在尝试找到一种能够在服务器上完成大部分工作的解决方案。
答案 0 :(得分:0)
要重新定义查询,您需要查找ID值,以便该ID的所有关键字组包含您要查找的所有搜索字词。
您可以使用Join
,而不是尝试使用GroupBy
创建ID的所有关键字组,然后当您拥有所有关键字的组共享ID时,它很简单足以过滤出该组包含所有搜索词的那些。
var query = keywords.GroupBy(keyword => keyword.Id)
.Where(group => searchTerms.All(term =>
group.Any(keyword => keyword.Keyword.StartsWith(term)))
.Select(group => group.Key);
答案 1 :(得分:0)
最终我能够让它生成我想要的SQL。即使这个问题对我来说是独一无二的,我也会发布我的解决方案。也许对某人有用。
LINQ
var term = searchTerms[0];
var keys = Keywords.Where (k => k.keyword.StartsWith(term));
for(var i=1; i < searchTerms.Length; i++)
{
var searchTerm = searchTerms[i];
keys =
from k1 in keys
join k2 in Keywords on k1.Id equals k2.Id
where k2.keyword.StartsWith(searchTerm)
select k1;
}
PRODUCED SQL:
-- Region Parameters
DECLARE @p__linq__0 VarChar(1000) = 'the%'
DECLARE @p__linq__1 VarChar(1000) = 'brown%'
DECLARE @p__linq__2 VarChar(1000) = 'fox%'
-- EndRegion
SELECT
[Extent1].[Id] AS [Id]
FROM [dbo].[Keywords] AS [Extent1]
INNER JOIN [dbo].[Keywords] AS [Extent2] ON [Extent1].[Id] = [Extent2].[Id]
INNER JOIN [dbo].[Keywords] AS [Extent3] ON [Extent1].[Id] = [Extent3].[Id]
WHERE ([Extent1].[keyword] LIKE @p__linq__0 ESCAPE '~') AND ([Extent2].[keyword] LIKE @p__linq__1 ESCAPE '~') AND ([Extent3].[keyword] LIKE @p__linq__2 ESCAPE '~')
当然我会做一些检查以确保在开始循环之前我有超过1个searchTerm。但你明白了。