簡體   English   中英

實體框架工作核心生成奇怪的SQL

[英]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.

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