讓我先說這是自學,我試圖自學LINQ和實體框架。我花了幾天的時間試圖將這個問題底部的SQL語句轉換爲LINQ,結果很糟糕。我還在底部包含了SQL圖。LINQ - 搜索一對多數組的完全匹配
我的目標是選擇所有與傳遞的字符串數組具有相同字符的故事。我不想要故事返回有額外的字符或缺少字符。這是我的軟弱LINQ技能也想出迄今:
var characters = new string[] { "Harry", "Tom" };
var cq = _context.TblCharacter.AsNoTracking().Where(c => characters.Contains(c.NameVc));
var q = from c in cq
join sc in _context.TblStoryCharacter.AsNoTracking()
on c.IdI equals sc.CharacterIdI
join s in _context.TblStory.AsNoTracking().Include(s => s.TblStoryCharacter).ThenInclude(sc => sc.CharacterIdINavigation)
on sc.StoryIdI equals s.IdI
where s.TblStoryCharacter.Count() == characters.Length
where s.TblStoryCharacter.Where(sc => characters.Contains(sc.CharacterIdINavigation.NameVc)).Count() == characters.Length
select s;
上面的代碼產卵一堆查詢(以下SQL事件探查器圖像),並加載大量的對象到內存中。這種情況下是否有任何LINQ魔術?
LINQ產生了疑問:
SELECT [t0].[StoryId_i]
FROM [tbl_story_character] AS [t0]
SELECT [sc1].[StoryId_i]
FROM [tbl_story_character] AS [sc1]
INNER JOIN [tbl_character] AS [sc.CharacterIdINavigation0] ON [sc1].[CharacterId_i] = [sc.CharacterIdINavigation0].[Id_i]
WHERE [sc.CharacterIdINavigation0].[Name_vc] IN ('Harry', 'Tom')
這是我一開始就試圖轉換爲LINQ的SQL:
select *
from tbl_story
where Id_i in (
select sc.StoryId_i
from tbl_story_character sc
inner join tbl_character c
on c.Id_i = sc.CharacterId_i
where c.Name_vc in ('Harry', 'Tom')
and not exists (
select *
from tbl_story_character subsc
inner join tbl_character subc
on subc.Id_i = subsc.CharacterId_i
where subc.Name_vc not in ('Harry', 'Tom')
and subsc.StoryId_i = sc.StoryId_i
)
group by sc.StoryId_i
having count(*) = 2
)
編輯: 這些模型由EFCore基於現有數據庫生成,每個模型都包含基於圖中外鍵的導航屬性。
在接受Jon Skeet和Munzer的建議之後的新LINQ。
from s in _context.TblStory.AsNoTracking()
.Include(s => s.AuthorIdINavigation)
.Include(s => s.TblStoryCharacter)
.ThenInclude(sc => sc.CharacterIdINavigation)
where s.TblStoryCharacter.All(sc => characters.Contains(sc.CharacterIdINavigation.NameVc))
where s.TblStoryCharacter.Count == 2
select s;
這會導致以下SQL似乎正確。
SELECT [s].[Id_i], [s].[AuthorId_i], [s].[Published_dt]
FROM [tbl_story] AS [s]
INNER JOIN [tbl_author] AS [t2] ON [s].[AuthorId_i] = [t2].[Id_i]
WHERE NOT EXISTS (
SELECT 1
FROM [tbl_story_character] AS [sc]
INNER JOIN [tbl_character] AS [sc.CharacterIdINavigation] ON [sc].[CharacterId_i] = [sc.CharacterIdINavigation].[Id_i]
WHERE ([s].[Id_i] = [sc].[StoryId_i]) AND [sc.CharacterIdINavigation].[Name_vc] NOT IN ('Harry', 'Tom')) AND ((
SELECT COUNT(*)
FROM [tbl_story_character] AS [t]
WHERE [s].[Id_i] = [t].[StoryId_i]
) = 2)
ORDER BY [s].[Id_i]
我想先開始試圖將查詢簡化爲仍然顯示問題的較短示例。你可以用* one * join和一個過濾器來重現問題嗎?基本上,找出它開始炸燬的地方。 –
看看「LINQ派生查詢」,我會說你正在使用EF核心,這當然不是一個很好的(複雜)查詢工具。但是你的LINQ查詢看起來很奇怪,所有這些混合的手動連接,導航屬性,跟蹤一個急切的加載相關結構。您已經顯示了數據庫圖表,但對於EF查詢,擁有相關表格的實體模型(類)更重要,您能否發佈它? –
@IvanStoev我是否應該離開核心直到它更成熟一些?我沒有任何限制,需要我利用核心。 – M3SSYM4RV1N