0

簡化示例:我有一個表,其中包含FirstNameLastName。我有興趣檢索所有全稱爲N的人,按照長度排序。爲了實現這一目標,我有這樣的代碼:在實體框架中選擇一個投影並按它篩選

var result = await Context.People 
       .Select(p => new PersonWithSalutation 
       { 
        FirstName = p.FirstName, 
        LastName = p.FirstName, 
        FullSalutation = p.FirstName + " " + p.LastName 
       }) 
       .Where(p => p.FullSalutation.Length < maxLength) 
       .OrderBy(p => p.FullSalutation) 
       .Take(maxResults) 
       .ToListAsync(); 

查詢看起來是這樣的:

SELECT TOP (10) 
    [Project1].[C1] AS [C1], 
    [Project1].[Name] AS [Name], 
    [Project1].[Id] AS [Id], 
    [Project1].[C2] AS [C2] 
    FROM (SELECT 
     [Extent1].[Id] AS [Id], 
     [Extent1].[Name] AS [Name], 
     1 AS [C1], 
     ...calculated stuff... AS [C2] 
     FROM [dbo].[People] AS [Extent1] 
     WHERE ...exactly the same stuff... <= @p__linq__3 
    ) AS [Project1] 
    ORDER BY [Project1].[C2] ASC 

這是卓有成效的,併產生一個單一的數據庫查詢。問題是計算投影,因爲它在結果查詢中出現兩次:一次在SELECT,然後在WHERE子句中出現。這個例子被簡化了,但在我的真實情況下,我正在進行沉重的數學運算,我寧願只計算一次。正如你在上面看到的,C2在order子句中被重用。我想對WHERE條款做同樣的處理,我認爲這會涉及另一個子查詢)。我將如何實現這一目標?

+0

我會認爲SQL Server來實現,該計算是一樣的,而不是做它在這種情況下兩次。你有理由相信它有嗎? – John

回答

1

由於查詢的構建過程非常不可預測,您可以通過查找期望的linq來花費大量時間。這就是爲什麼,我提供了另一種方法。將FullSalutation財產添加到您的POCO類中,並在FirstNameLastName發生更改時通過DB計算(Computed)。在這種情況下,計算將在確實需要時執行,無需重複,如您所願。

public class POCO 
{ 
    public int ID { get; set; } 
    public string FirstName { get; set; } 
    public string LastName { get; set; } 

    [DatabaseGenerated(DatabaseGeneratedOption.Computed)] 
    public string FullSalutation { get; private set; } 
} 

然後添加新的遷移:

public override void Up() 
{ 
    //AddColumn("dbo.People", "FullSalutation", x => x.String()); 
    Sql("ALTER TABLE dbo.People ADD FullSalutation AS FirstName + ' ' + LastName"); 
} 
public override void Down() 
{ 
    DropColumn("dbo.People", "FullSalutation"); 
} 

最後你的查詢將是這樣的:

var result = await Context.People 
      .Where(p => p.FullSalutation.Length < maxLength) 
      .Select(p => new PersonWithSalutation 
      { 
        FirstName = p.FirstName, 
        LastName = p.LastName, 
        FullSalutation = p.FullSalutation 
      }).OrderBy(p => p.FullSalutation).Take(maxResults).ToListAsync();