[英]entity framwork core generates weird sql
我正在嘗試優化現有的LINQ查詢。 我有以下實體類型(簡化)
public class Account
{
public int Id { get; set; }
public IEnumerable<OpportunityInfo> Opportunities { get; set; }
}
public class Opportunity
{
public int Id { get; set; }
public string Name { get; set; }
public bool Active { get; set; }
public IEnumerable<Quote> Quotes { get; set; }
}
public class Quote
{
}
這是“機會到報價”的標准層次結構。 沒什么特別的。 我在ASP.NET Core控制器索引方法上使用以下查詢。 我從報價開始,然后反向工作,因為查詢和機會報價之間必須存在基於報價的動態查詢邏輯。 否則,我將從頭開始。
var query = from o in Quotes select o;
其他查詢邏輯(過濾和排序)
var opportunityQuotes = from o in query
group o by new
{
accountId = o.Opportunity.AccountId,
accountName = o.Opportunity.Account.Name,
active = o.Opportunity.Account.Active,
}
into p
select new
{
Id = p.Key.accountId,
Name = p.Key.accountName,
Active = p.Key.active,
Opportunities =
(from q in p
group q by new
{
Id = q.Opportunity.Id,
Name = q.Opportunity.Name,
Active = q.Opportunity.Active
}
into r
select new
{
Name = r.Key.Name,
Id = r.Key.Id,
Active = r.Key.Active,
Quotes = r
})
};
opportunityQuotes.Dump();
該查詢生成以下SQL。
SELECT [o].[Id], [o].[ARRValue], [o].[AccountId], [o].[AdjustedArr], ...
FROM [Quotes] AS [o]
LEFT JOIN [Opportunities] AS [o.Opportunity] ON [o].[OpportunityId] = [o.Opportunity].[Id]
INNER JOIN [Accounts] AS [o.Account] ON [o].[AccountId] = [o.Account].[Id]
ORDER BY [o].[AccountId], [o.Account].[Name], [o.Account].[Active]
GO
SELECT [q.Opportunity0].[Id], [q.Opportunity0].[Name], [q.Opportunity0].[Active]
FROM [Opportunities] AS [q.Opportunity0]
GO
SELECT [q.Opportunity0].[Id], [q.Opportunity0].[Name], [q.Opportunity0].[Active]
FROM [Opportunities] AS [q.Opportunity0]
GO
SELECT [q.Opportunity0].[Id], [q.Opportunity0].[Name], [q.Opportunity0].[Active]
FROM [Opportunities] AS [q.Opportunity0]
GO
實際上,它會為每個機會生成查詢,但是為了簡潔起見,我將其省略。 我認為EF不應為每個報價單獨生成查詢。 實際上,如果我在查詢中注釋掉.Name和.Active鍵參數,如下所示:
group q by new
{
Id = q.Opportunity.Id,
// Name = q.Opportunity.Name,
// Active = q.Opportunity.Active
}
並在select子句中注釋掉對應的變量,它會生成更清晰的sql。
SELECT [o].[Id], [o].[ARRValue], [o].[AccountId], ...
FROM [Quotes] AS [o]
LEFT JOIN [Opportunities] AS [o.Opportunity] ON [o].[OpportunityId] = [o.Opportunity].[Id]
INNER JOIN [Accounts] AS [o.Account] ON [o].[AccountId] = [o.Account].[Id]
ORDER BY [o].[AccountId], [o.Account].[Name], [o.Account].[Active]
GO
我感到困惑的原因是.Name和.Active完全在同一對象中,它們以與.Id字段相同的方式在鍵中分組,因此我不明白為什么EF會通過以下方式更改其行為添加其他組值。 有人可以解釋這種行為嗎?
讓我們退后一步,從不同的角度看待它:如果您要手動編寫SQL查詢,並且想獲取一個查詢中所需的所有數據,您將獲得很多重復的數據來尋找機會和客戶。 您也可以在這里執行以下操作:
var query = from o in Quotes select o;
var oppQuotes = from o in query
select new
{
AccountId = o.Opportunity.Account.Id,
AccountName = o.Opportunity.Account.Name,
// ... and so on, with all the fields you expect to use.
OpportunityId = o.Opportunity.Id,
OpportunityName = o.Opportunity.Name,
// ... and so on, with all the fields you expect to use.
QuoteId = o.Id,
QuoteName = o.Name,
// ... and again, you get the point.
};
然后,只需對其執行.AsEnumerable()
,然后在C#代碼中執行分組。 無論如何,數據庫將無法優化任何內容。
var opportunityQuotes = from q in oppQuotes.AsEnumerable()
group q by new { q.AccountId, q.AccountName }
into accounts
// ... and so on.
對於您的問題, 為什么 EF創建了奇怪的查詢,我很茫然。
無論如何,最好考慮如何創建sql代碼以最有效地獲取所需數據,而不必依靠EF來“做正確的事情”。 在許多情況下,它會完全炸掉您的臉。 當您需要查詢時,請考慮一下SQL,然后將其轉換為EF代碼。 如果您明確地說出自己想要什么,那么您會得到的。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.