我正在尝试从旧的经典ASP项目中复制任何现有查询的结果。查询非常简单。
SELECT DISTINCT TOP 10 MAX(H.HistID) as MaxHID, C.CompanyID,C.CompanyName, P.ProsID, P.ProsName, P.Online
FROM HISTORY H, PROSPECTUS P, COMPANY C
WHERE H.ProsID = P.ProsID
and P.CompanyID = C.CompanyID
and H.UserID = 2712
GROUP BY C.CompanyID, C.CompanyName, P.ProsID, P.ProsName, P.Online
ORDER BY MaxHID DESC
我(至少试图)使用以下查询使用Entity Framework复制它:
MyContext.HistoryItems.Where(h => h.UserId == userId)
.GroupBy(h => new { h.Prospectus.Family.Id, h.ProsId })
.Select(h => new { Max = h.Max(i => i.Id), Item = h.FirstOrDefault() })
.OrderByDescending(h => h.Max)
.Take(10)
.Select(h => h.Item);
(GroupBy()
旨在复制原始查询中的DISTINCT
行为。)
此查询会生成完全相同的数据,但需要大约10秒才能执行。我查看了EF生成的查询,这是一个怪物。
SELECT TOP (10)
[Project6].[HistId] AS [HistId],
[Project6].[UserID] AS [UserID],
[Project6].[ProsID] AS [ProsID],
[Project6].[HDate] AS [HDate],
[Project6].[ProsDocId] AS [ProsDocId]
FROM ( SELECT
[Project5].[HistId] AS [HistId],
[Project5].[UserID] AS [UserID],
[Project5].[ProsID] AS [ProsID],
[Project5].[HDate] AS [HDate],
[Project5].[ProsDocId] AS [ProsDocId],
[Project5].[C1] AS [C1]
FROM ( SELECT
[Project4].[HistId] AS [HistId],
[Project4].[UserID] AS [UserID],
[Project4].[ProsID1] AS [ProsID],
[Project4].[HDate] AS [HDate],
[Project4].[ProsDocId] AS [ProsDocId],
(SELECT
MAX([Extent5].[HistId]) AS [A1]
FROM [dbo].[History] AS [Extent5]
INNER JOIN [dbo].[Prospectus] AS [Extent6] ON [Extent5].[ProsID] = [Extent6].[ProsId]
WHERE ([Extent5].[UserID] = @p__linq__0) AND (([Project4].[CompanyId] = [Extent6].[CompanyId]) OR (1 = 0)) AND ([Project4].[ProsID] = [Extent5].[ProsID])) AS [C1]
FROM ( SELECT
[Project2].[ProsID] AS [ProsID],
[Project2].[CompanyId] AS [CompanyId],
[Limit1].[HistId] AS [HistId],
[Limit1].[UserID] AS [UserID],
[Limit1].[ProsID] AS [ProsID1],
[Limit1].[HDate] AS [HDate],
[Limit1].[ProsDocId] AS [ProsDocId]
FROM (SELECT
@p__linq__0 AS [p__linq__0],
[Distinct1].[ProsID] AS [ProsID],
[Distinct1].[CompanyId] AS [CompanyId]
FROM ( SELECT DISTINCT
[Extent1].[ProsID] AS [ProsID],
[Extent2].[CompanyId] AS [CompanyId]
FROM [dbo].[History] AS [Extent1]
INNER JOIN [dbo].[Prospectus] AS [Extent2] ON [Extent1].[ProsID] = [Extent2].[ProsId]
WHERE [Extent1].[UserID] = @p__linq__0
) AS [Distinct1] ) AS [Project2]
OUTER APPLY (SELECT TOP (1)
[Extent3].[HistId] AS [HistId],
[Extent3].[UserID] AS [UserID],
[Extent3].[ProsID] AS [ProsID],
[Extent3].[HDate] AS [HDate],
[Extent3].[ProsDocId] AS [ProsDocId]
FROM [dbo].[History] AS [Extent3]
INNER JOIN [dbo].[Prospectus] AS [Extent4] ON [Extent3].[ProsID] = [Extent4].[ProsId]
WHERE ([Extent3].[UserID] = @p__linq__0) AND (([Project2].[CompanyId] = [Extent4].[CompanyId]) OR (1 = 0)) AND ([Project2].[ProsID] = [Extent3].[ProsID]) ) AS [Limit1]
) AS [Project4]
) AS [Project5]
) AS [Project6]
ORDER BY [Project6].[C1] DESC
我的Linq查询显然有问题会导致EF产生如此混乱。我创建的EF查询是否效率不高?
答案 0 :(得分:5)
每当分组发挥作用时,我更喜欢高于语法的查询语法。
当你这样做......
(
from h in MyContext.HistoryItems
where h.UserId == userId)
group h by new {
h.CompanyId,
Comapany = h.Company.Name,
Prospectus = h.Prospectus.Name,
h.Prospectus.Online,
h.ProsId
} into grp
select new {
Max = grp.Max(i => i.Id),
grp.Key.CompanyId,
grp.Key.Comapany,
grp.Key.Prospectus,
grp.Key.Online,
grp.Key.ProsId,
} into proj
orderby proj.Max descending
select proj
).Distinct().Take(10)
...查询应该更清晰,因为现在你只选择将出现在最终投影中的属性,并且FirstOrDefault()
没有被混淆。连接甚至不存在,因为我让EF使用h.Company
等导航属性来计算联接。
请注意,我尝试重现SQL查询。 LINQ查询对我来说看起来不一样。
答案 1 :(得分:3)
试试这个,我不确定它是100%正常工作
MyContext.HistoryItems
.Join(MyContext.ProspectusItems, a => a.ProsId, b => b.ProsId, (a,b) => new {a, b})
.Join(MyContext.CompanyItems, a => a.b.CompanyId, b => b.CompanyId, (a,b) => new {a, b})
.Where(a => a.a.a.UserId == 2712)
.GroupBy(x => new {x.b.CompanyID, x.bCompanyName, x.a.b.ProsID, x.a.b.ProsName, x.a.b.Online)
.Select(x => new {maxHistID = x.Max(x => x.a.a.HistID), x.Key.x.b.CompanyID, x.Key.x.bCompanyName, x.Key.x.a.b.ProsID, x.Key.x.a.b.ProsName, x.Key.x.a.b.Online).
.OrderByDesc(x => x.MaxHID)
.Take(10)
答案 2 :(得分:0)
试试这个,这是一个更直接可比的实现:
MyContext.HistoryItems.Where(h => h.UserId == userId)
GroupBy(h => new {h.Prospectus.Family.Id, h.ProsId},h=>h.HistId,(key,vals)=>new {key.Id, key.ProsId,Max=vals.Max()})
.OrderByDescending(h => h.Max)
.Take(10)