簡體   English   中英

使用LINQ進行實體動態聯接

[英]Using LINQ to Entities dynamic JOIN

假設您有一個關鍵字表。 為簡單起見,我們只說它有2個字段,一個ID整數,關鍵字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,然后再加入我的結果。 這可能會產生巨大的內存需求,我正在嘗試找到一種解決方案,該解決方案可以滿足我在服務器上的大部分需求。

要改寫您的查詢,您要查找ID值,以便該ID的所有關鍵字組包含您要查找的所有搜索詞。

您可以使用GroupBy ,而不是嘗試使用Join為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);

最終,我能夠得到它來生成我想要的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;
}

產生的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 '~')

當然,在開始循環之前,我會進行一些檢查以確保我擁有多個searchTerm。 但是你明白了。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM