[英]Convert T-SQL to Fluent Linq C# with the same SQL generated output
我在我的數據庫中有以下架構:
關鍵是要為每個用戶提供他每個線程的最后一次讀取日期時間。
如果需要,我還可以通過論壇和Universe查看此日期並進行匯總。
如果所有線程都被Read
,則論壇被視為已Read
。
如果用戶的Lastview
或等於上次創建的發布日期(來自Post.CreatedAt
),則線程被視為已Read
。
我已經發出以下T-SQL請求來實現每個論壇的目標:
SELECT
F.Id,
CASE WHEN SUM(V.IsRead) = COUNT(V.IsRead) THEN 1 ELSE 0 END AS IsRead
FROM Forum F
LEFT JOIN Thread T ON T.Id_Forum = F.Id
LEFT JOIN
(
SELECT
P.Id_Thread,
CASE WHEN MAX(P.CreatedAt) < MAX(V.LastView) THEN 1 ELSE 0 END AS IsRead
FROM Post P
INNER JOIN Thread T ON P.Id_Thread = T.Id
INNER JOIN Forum F ON T.Id_Forum = F.Id
LEFT JOIN Thread_View V ON P.Id_Thread = V.Id_Thread AND V.Id_User = @Id_User
WHERE F.Id_Universe = @Id_Universe
GROUP BY P.Id_Thread
) V ON T.Id = V.Id_Thread
WHERE F.Id_Universe = @Id_Universe
GROUP BY F.Id
ORDER BY F.Id
它完美地工作, 但是 ,我現在想要使用EntityFramework
從Linq
創建這個請求...而且我被卡住了......
這是我所做的,但它產生了一個非常復雜的查詢,我害怕性能......
var viewsQuery = context.Posts
.Where(p => p.Thread.Forum.Id_Universe == idUniverse)
.GroupJoin
(
context.Thread_Views.Where(v => v.Id_User == idUser),
p => p.Id_Thread,
v => v.Id_Thread,
(p, v) => new { Id_Thread = p.Id_Thread, Id_Forum = p.Thread.Id_Forum, CreatedAt = p.CreatedAt, LastView = v.Max(_v => _v.LastView) }
)
.Select(r => new { Id_Thread = r.Id_Thread, Id_Forum = r.Id_Forum, IsRead = r.CreatedAt < r.LastView });
var forumQuery = context.Forums.Where(f => f.Id_Universe == idUniverse).GroupJoin
(
viewsQuery.DefaultIfEmpty(),
forum => forum.Id,
view => view.Id_Forum,
(forum, views) => new
{
Forum = forum.Id,
IsRead = views.Any() && views.All(v => v.IsRead),
}
);
linq生成的SQL輸出是這樣的(稍微編輯得更易讀),它太丑了......
SELECT
[Project1].[Id] AS [Id],
CASE WHEN
(
(
EXISTS
(
SELECT
1 AS [C1]
FROM ( SELECT 1 AS X ) AS [SingleRowTable1]
INNER JOIN
(
SELECT [Extent3].[Id_Forum] AS [Id_Forum], [Extent4].[Id_Universe] AS [Id_Universe]
FROM [dbo].[Post] AS [Extent2]
INNER JOIN [dbo].[Thread] AS [Extent3] ON [Extent2].[Id_Thread] = [Extent3].[Id]
INNER JOIN [dbo].[Forum] AS [Extent4] ON [Extent3].[Id_Forum] = [Extent4].[Id] ) AS [Join2] ON 1 = 1
WHERE ([Join2].[Id_Universe] = 3) AND ([Project1].[Id] = [Join2].[Id_Forum])
)
)
AND
(
NOT EXISTS
(
SELECT
1 AS [C1]
FROM ( SELECT 1 AS X ) AS [SingleRowTable2]
INNER JOIN
(
SELECT
[Project3].[CreatedAt] AS [CreatedAt],
[Project3].[Id_Forum] AS [Id_Forum],
(
SELECT MAX([Extent8].[LastView]) AS [A1]
FROM [dbo].[Thread_View] AS [Extent8]
WHERE ([Extent8].[Id_User] = 79775) AND ([Project3].[Id_Thread] = [Extent8].[Id_Thread])
) AS [C1]
FROM
(
SELECT
[Extent5].[Id_Thread] AS [Id_Thread],
[Extent5].[CreatedAt] AS [CreatedAt],
[Extent6].[Id] AS [Id],
[Extent6].[Id_Forum] AS [Id_Forum]
FROM [dbo].[Post] AS [Extent5]
INNER JOIN [dbo].[Thread] AS [Extent6] ON [Extent5].[Id_Thread] = [Extent6].[Id]
INNER JOIN [dbo].[Forum] AS [Extent7] ON [Extent6].[Id_Forum] = [Extent7].[Id]
WHERE [Extent7].[Id_Universe] = 3
) AS [Project3]
) AS [Project4] ON 1 = 1
WHERE
(
(
(
CASE
WHEN ([Project4].[CreatedAt] < [Project4].[C1]) THEN cast(1 as bit)
WHEN ( NOT ([Project4].[CreatedAt] < [Project4].[C1])) THEN cast(0 as bit)
END
) <> 1
)
OR
(
CASE
WHEN ([Project4].[CreatedAt] < [Project4].[C1]) THEN cast(1 as bit)
WHEN ( NOT ([Project4].[CreatedAt] < [Project4].[C1])) THEN cast(0 as bit)
END IS NULL
)
) AND ([Project1].[Id] = [Project4].[Id_Forum])
)
)
) THEN cast(1 as bit)
ELSE cast(0 as bit) END AS [C1]
FROM
(
SELECT
[Extent1].[Id] AS [Id]
FROM [dbo].[Forum] AS [Extent1]
WHERE [Extent1].[Id_Universe] = 3
) AS [Project1]
編輯 :發現一個工作的linq查詢具有相同的結果,但它是如此丑陋,我非常害怕性能...
var forumsWhichAreUnread = from forum on context.Forums
let isUnRead = forum.Threads.All(thread =>
thread.ThreadViews
.Where(view => view.UserId = userId)
.Max(view => view.Lastview)
<
thread.Posts.Max(post => post.CreatedAt))
select new {forum, isUnRead};
翻譯
在context.Forums
獲取每個forum
只給我每個線程的論壇...
最大的threadview .LastView
時間小於最新發布日期。
選擇那些forum
。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.