2018 年 7 月

第 33 卷,第 7 期

本文章是由機器翻譯。

資料點 - EF Core 2.1 查詢類型

藉由Julie Lerman

Julie LermanEF Core 2.1 隆重推出 !而且有許多很棒的新功能和增強功能。而不是接管整份雜誌告訴您,我將會與您分享新的查詢類型功能,這可讓您更輕鬆地查詢資料庫,而不需要具有索引鍵的屬性,以取用結果,則為 true 的實體。

查詢類型,可以撰寫查詢資料庫檢視,以及執行預存程序與 EF Core,但有幾項限制。檢視中,您必須依賴 EF Core 並不知道檢視和資料表之間的差異,您的資料庫中的事實。您無法建立實體,屬於您的 DbContext 模型、 為這些實體建立 DbSets,然後撰寫這些 DbSets 查詢。不過,需要注意的事項很多隨附該工作流程,例如需要請小心不要編輯產生的物件和不小心導致嘗試執行 update 命令,將您的資料庫中失敗,除非您的檢視是可更新的 SaveChanges。執行時使用 FromSql 方法的預存程序,會再次要求您將繫結,則為 true 的實體資料模型,這意味著您真的不需要有的資料模型中加入額外型別中的結果。

新的查詢類型可讓您更輕鬆使用檢視、 預存程序和其他方法來查詢資料庫的路徑。這是因為查詢類型可讓您可讓 EF Core 互動沒有索引鍵屬性和對應的型別沒有主索引鍵的資料庫物件。EF 一直都相依於索引鍵,因此這是 EF core 了一大步。此外,查詢類型將協助您避免變更追蹤程式的任何互動,因此您不必在程式碼,以防止意外執行階段例外狀況是不可更新的實體與相關的應用程式中新增。您甚至可以將對應至資料表,迫使他們處於唯讀模式中使用的查詢類型。

在本文中我瀏覽三種查詢類型所啟用的功能:

  • 查詢資料庫檢視
  • 另一個稱為 「 定義查詢 」 的新功能
  • 擷取與非實體類型的 FromSql 查詢的結果

查詢類型的重要讓知道型別應該視為查詢類型的 DbContext ModelBuilder。您可以建立 DbQuery 屬性內容中,或是使用 ModelBuilder.Query 方法。兩者都是新項目。

如果您已使用 EF 或 EF Core 完全,您應該熟悉 DbSet,EF 類別,可讓您查詢和更新 DbContext 透過特定型別的實體。DbQuery 是 DbSet 包裝非實體類型,並可讓您執行唯讀查詢,針對檢視表和資料表的表親。而這些類型包裝在 DbQuery 查詢類型。

DbQuery 的 EF Core 慣例是類似於 DbSet EF Core 預期 DbQuery 屬性,以符合它所對應之資料庫物件名稱的名稱。

兩個點,您應該注意的是,移轉將無法建立檢視,根據對應,而且 EF Core 無法進行反向工程的檢視 (還)。

對應至和查詢資料庫檢視

我將使用 DbQuery 第一個範例中,對應到資料庫檢視,並從該查詢。此 DbQuery 假設沒有類別已定義,因為名稱 AuthorArticleCounts 為資料庫中的檢視:

public DbQuery<AuthorArticleCount>
  AuthorArticleCounts{get;set;}

這單獨可讓您查詢資料庫檢視。讓我們倒帶,不過,若要查看模型中所示**[圖 1**。

[圖 1 的範例模型的實體類別

public class Magazine
{
  public int MagazineId { get; set; }
  public string Name { get; set; }
  public string Publisher { get; set; }
  public List<Article> Articles { get; set; }
}
public class Article
{
  public int ArticleId { get; set; }
  public string Title { get; set; }
  public int MagazineId { get; set; }
  public DateTime PublishDate { get;  set; }
  public Author Author { get; set; }
  public int AuthorId { get; set; }
}
public class Author
{
  public int AuthorId { get; set; }
  public string Name { get; set; }
  public List<Article> Articles { get; set; }
}

我使用簡單的模型具有三個實體來管理發行集:雜誌文章,作者。

在 [我的資料庫,除了雜誌文章,作者資料表中,我有檢視,稱為 AuthorArticleCounts,定義要傳回的名稱和作者所撰寫的文章數目:

SELECT
  a.AuthorName,
  Count(r.ArticleId) as ArticleCount
from Authors a
  JOIN Articles r on r.AuthorId = a.AuthorId
GROUP BY a.AuthorName

我也建立了符合之結構描述的檢視結果的 AuthorArticleCount 類別。在類別中,我做的屬性 setter 私用,以便釐清,這個類別是唯讀的雖然 EF Core 不會不斷嘗試追蹤或保存資料之查詢類型。

public class AuthorArticleCount
{
  public string AuthorName { get; private set; }
  public int ArticleCount { get; private set; }
}

資料庫中的檢視位置,並設計成使用其結果的類別,我只需要將它們一起對應是我 DbContext DbQuery 屬性 — 我先前所示範的相同範例:

public DbQuery<AuthorArticleCount> AuthorArticleCounts{get;set;}

現在 EF Core 會很高興使用 AuthorArticleCount 類別中,即使它有沒有索引鍵的屬性,因為 EF Core,了解這是查詢類型。您可以使用它來撰寫和執行查詢資料庫檢視。

比方說,這個簡單的 LINQ 查詢:

var results=_context.AuthorArticleCounts.ToList();

將會導致下列的 SQL 傳送到我的 SQLite 資料庫:

SELECT "v"."ArticleCount", "v"."AuthorName"
  FROM "AuthorArticleCounts" AS "v"

結果會是一組 AuthorArticleCount 物件中所示**[圖 2**。

一對一查詢的結果
[圖 2 一對一的查詢結果

而且用來執行查詢的內容的 ChangeTracker 完全不會察覺這些物件。

這是比過去 EF Core 與 Entity Framework 實作資料庫檢視已視為資料表,其結果必須是實體,您必須注意不要不小心將其設為追蹤與變更追蹤程式太多更佳的體驗。

很可能不需要預先定義 DbQuery DbContext 類別中的執行查詢。DbSet 允許,也與 DbContext 執行個體的 Set 方法。DbQuery 中,您可以撰寫查詢:

var results=_context.Query<AuthorArticleCount>().ToList();

設定查詢類型對應

此 DbQuery 合作輕鬆,因為所有項目會遵循慣例。當 DbSets 和其實體不遵循 EF Core 慣例時,您可以在 OnModelCreating 方法中指定正確的對應使用 Fluent API 或資料註解。您首先要找出您想要使用 ModelBuilder 實體方法會影響模型中的實體。就像 DbSet 獲得 cousin DbQuery 中的,實體方法也會有新的 cousin:查詢。AuthorArticleCounts DbQuery 指向不同的名稱,並使用新 ToView 方法 (類似於 ToTable 方法) 的檢視中使用的查詢方法的範例如下:

modelBuilder.Query<AuthorArticleCount>().ToView(
  "View_AuthorArticleCounts");

查詢 < T > 方法會傳回 QueryTypeBuilder 物件。ToView 是擴充方法。有多種方法,您可以使用精簡查詢類型時。QueryTypeBuilder 具有 EntityTypeBuilder 方法的子集:HasAnnotation、 HasBaseType、 HasOne、 HasQueryFilter、 IgnoreProperty 和 UsePropertyAccessMode。沒有關於 ToView 和 ToTable 反白顯示為建議的查詢類型文件中的工具提示的不錯說明 (bit.ly/2kmQhV8)。

關聯性中的查詢類型

請注意 HasOne 方法。它可能會是相依性 (也稱為 「 子 」) 與實體,一對一或一對多的關聯性中的查詢類型但仍不會有另一種查詢類型。也請注意,查詢類型不幾乎靈活度不如實體關聯性,這是在我看來合理。而且,您必須以特定方式設定關聯性。

我會先使用作者實體與 AuthorArticleCount 之間的一對一關聯性。實作此最重要的規則如下:

  • 查詢類型都必須有回到關聯性另一端的導覽屬性。
  • 實體不能有導覽屬性查詢型別。

在後者的情況下,如果您要加入 AuthorArticleCount 屬性為 [作者] 內容會認為 AuthorArticleCount 是實體和模型產生器將會失敗。

我已增強具有兩項變更的模型:

首先,我會修改以包含 [作者] 內容 AuthorArticleCount:

public Author Author { get; private set; }

然後我加入作者和 AuthorArticleCount 之間的一對一對應:

modelBuilder.Query<AuthorArticleCount>()
            .HasOne<Author>()
            .WithOne();

我現在可以執行 LINQ 查詢,積極式載入 [作者] 導覽屬性,例如:

var results =_context.AuthorArticleCounts.Include("Author").ToList();

所得的結果顯示在 [圖 3] 中。

積極式載入 [查詢類型的實體之間的一對一關聯性的結果
[圖 3 的積極式載入 [查詢類型的實體之間的一對一關聯性的結果

一對多關聯性中的查詢類型

一對多關聯性也需要查詢類型的相依端,永遠不會 (也稱為父系) 的主體。若要探索這種情況,我可以建立新的檢視稱為 ArticleView 資料庫中的發行項資料表:

CREATE VIEW ArticleView as select Title, PublishDate, MagazineId from Articles;

和我建立了 ArticleView 類別:

public class ArticleView
{
  public string Title { get; set; }
  public Magazine Magazine { get; set; }
  public int MagazineId { get; set; }
  public DateTime PublishDate { get; set; }
}

最後,我指定 ArticleView 是查詢類型,並定義與雜誌的實體,其中雜誌可以有許多 ArticleViews 及其關聯性:

modelBuilder.Query<ArticleView>().HasOne(a => a.Magazine).WithMany();

現在我可以執行查詢來擷取資料的圖形。我要再次使用 Include 方法。請記住,沒有任何參考查詢型別在雜誌類別中,因此您無法使用其 ArticleViews 雜誌的圖形查詢,並查看這些圖表。您可以只從瀏覽 ArticleView magazine,因此這是您可以執行的查詢類型:

var articles=_context.Query<ArticleView>().Include(m=>m.Magazine).ToList();

請注意,我就沒有建立 DbQuery,所以我在我的查詢中使用的查詢方法。

HasOne,您會在找到的 API 文件bit.ly/2Im8UqR,提供有關使用這個方法的進一步詳細資訊。

新定義的查詢功能

除了 ToView,一個新的方法上 QueryTypeBuilder 永遠不會存在於上 EntityTypeBuilder,且是 ToQuery。ToQuery 可讓您直接在 DbContext 中定義的查詢,以及這類查詢指 「 定義查詢 」。 您可以撰寫 LINQ 查詢,並撰寫定義查詢時,甚至使用 FromSql。Andrew Peters,EF 小組的說明,「 ToQuery 的其中一種用法是使用記憶體中的提供者進行測試。如果我的應用程式正在使用資料庫檢視,我也可以定義針對記憶體中時,才會使用 ToQuery。如此一來我可以模擬用於測試的 [資料庫] 檢視。 」

若要開始,我建立 MagazineStatsView 類別來使用查詢的結果:

public class MagazineStatsView
{
  public MagazineStatsView(string name, int articleCount, int authorCount)
  {
    Name=name;
    ArticleCount=articleCount;
    AuthorCount=authorCount;
  }
  public string Name { get; private set; }
  public int ArticleCount { get; private set; }
  public int AuthorCount{get; private set;}
}

我在 OnModelCreating 中雜誌的實體,該查詢建立定義的查詢,然後建置 MagazineStatsView 物件,從結果:

modelBuilder.Query<MagazineStatsView>().ToQuery(
      () => Magazines.Select(  m => new MagazineStatsView(
                     m.Name,
                     m.Articles.Count,
                     m.Articles.Select(a => a.AuthorId).Distinct().Count()
                    )
                )
  );

我也可以建立 DbQuery 讓我定義的新查詢更容易被找到,但是我想要看到,我仍然可以使用這個不明確的 DbQuery。  以下是 MagazineStatsView 的 LINQ 查詢。它一律會處理所定義的查詢:

var results=_context.Query<MagazineStatsView>().ToList();

我已用來植入資料庫時,所顯示的查詢結果的資料為基礎**[圖 4**,正確地顯示兩個發行項和一個唯一的作者,MSDN magazine 和兩個唯一作者的新增 Yorker 一起的兩個發行項。

使用定義的查詢進行查詢的結果
[圖 4 的查詢使用 [定義查詢的結果

擷取 FromSql 導致非實體類型

在舊版的 Entity Framework 中,則可以執行未經處理的 SQL,並擷取這些結果中隨機的類型。我們很接近能夠執行這種類型的查詢,因為查詢類型。EF Core 2.1 中,您想要擷取的原始 SQL 查詢結果的型別不必是實體,但它仍有可以用做為查詢類型的模型。

沒有唯一的例外,這是可能會 (有限制的許多) 要傳回匿名型別。即使是有限的支援仍然十分有用,因此很值得注意。以下是可傳回匿名型別使用 FromSql 和原始的 SQL 查詢的查詢:

context.Authors.FromSql("select authorid,authorname from authors").ToList();

藉由查詢實體傳回匿名型別只適用於投影包含 DbSet 所表示之類型的主索引鍵。如果我並未包含 AuthorId,執行階段錯誤會抱怨 AuthorId 未在投影中。或如果我一開始有內容。Magazines.FromSql 剛剛提到的相同查詢中,執行階段錯誤會抱怨 MagazineId 無法使用。

充分利用這項功能是預先定義的類型,並請確定知道該型別,藉由定義 DbQuery,或在 OnModelCreating 中指定型別的 modelBuilder.Query DbContext。然後您可以使用 FromSql 查詢,並擷取結果。因為稍微經過人為操作的範例中,或也許我應該說更自然一些我已經使用的範例,以下是新的類別,發行者,並不是實體或我 PublicationsContext 的一部分:

public class Publisher
{  
  public string Name { get; private set; }
  public int YearIncorporated { get; private set; }
}

也是唯讀的類別,因為我有另一個應用程式,我會維護 「 發行者 」 的資料。

我建立了名為 「 發行者 」,在我的內容,DbQuery < 發行者 >,且我現在可以使用該執行原始的 SQL 查詢:

var publishers=_context.Publishers
                  .FromSql("select name, yearfounded from publishers")
                  .ToList();

原始 SQL 也可以執行預存程序的呼叫。只要結果的結構描述相符的型別 (在此情況下,「 發行者 」),您可以這麼做,甚至傳入的參數。

波蘭文置於 EF Core

如果您已久使用 EF Core,直到它已備妥,最後到達的時間。EF Core 2.0 的功能,做了一大步,和 2.1 版現在會包含實際波蘭文放入產品的功能。從 EF6 才會出現在 EF Core 功能等候已因為部分的事實,EF 小組有不只會複製舊的實作,但找到更聰明、 更具功能性的實作。查詢類型是一個絕佳的範例,相較於在舊版的 Entity Framework 所支援檢視和原始 SQL 的方式。請務必查看 EF Core 2.1 中的其他新功能,藉由讀取的 EF Core 文件的 「 新增功能在 EF Core 2.1 中 」 區段bit.ly/2IhyHQR


Julie LermanMicrosoft 地區主管、 Microsoft MVP、 軟體小組指導,以及位於 Vermont 山區顧問。您可以找到其呈現在資料存取和使用者群組和所做的心得世界各地的其他主題。在她部落格thedatafarm.com/blog和以及 Code First DbContext 版本中的,所有從 O'Reilly Media 是"程式設計 Entity Framework"的作者。在 Twitter 上關注她: @julielerman ,請參閱在她 Pluralsight 課程juliel.me/PS 影片

感謝下列 Microsoft 技術專家來檢閱這篇文章:Andrew Peters
Andrew Peters 是 Entity Framework 小組的首席工程師。在他的小組 9 年中,Andrew 曾經參與,以及其他項目、 LINQ、 Code First 移轉,但 EF core 的架構潛在客戶的其中一個。他在空閒時候 Andrew 工作之餘喜歡遊戲吉他,烹飪,以及與家人年輕花的時間。


MSDN Magazine 論壇中的這篇文章的討論