JULY 2018

VOLUME 33 NUMBER 7

データ ポイント - EF Core 2.1 の Query Type

によってJulie Lerman

Julie LermanEF Core 2.1 では、ここです。多数の優れた新機能や機能強化。クエリの種類の新しい機能を共有します、すべてをご紹介全体 magazine を引き継ぎではなく、結果を処理するキーのプロパティを持つ場合は true。 のエンティティをしなくても、データベースを簡単に照会することです。

クエリの種類の前にデータベース ビューに対してクエリを記述して、EF core でのストアド プロシージャを実行できましたが、制限事項がありました。ビュー、EF Core がデータベースのビューとテーブルの間の違いを認識しないという事実に依存する必要があります。エンティティを作成する DbContext モデルの一部であった、DbSets をこれらのエンティティに対して作成、およびそれらの DbSets に対するクエリを作成し、可能性があります。多くの注意事項の結果のオブジェクトを編集しないように注意することと、ビューが更新可能な場合を除き、データベースでは失敗 update コマンドを実行しようとする SaveChanges を誤って原因など、そのワークフローに付属します。FromSql メソッドを使用してストアド プロシージャを実行するときにもう一度、結果が存在する必要はありませんでした本当に、データ モデルに追加の型を追加するもので、データ モデルの一部であった場合は true。 エンティティを関連付ける必要があります。

新しいクエリの種類は、ビュー、ストアド プロシージャ、および、データベースのクエリの他の手段を使用するパスを簡単にできます。これは、クエリの種類を使用すると、EF core にキー プロパティとマップがない型と対話するためにプライマリ キーがないデータベース オブジェクト。EF ではこれは、EF Core の大きな一歩依存キーでは、いつもします。さらに、クエリの種類では更新可能なエンティティに関連する不注意によるランタイム例外からアプリケーションを保護するためのコードを追加する必要はありませんので、相互作用を変更トラッカーを避けることができます。読み取り専用にすることを強制して、テーブルにマップするクエリの種類を使用することもできます。

この記事では、クエリの種類で有効化する 3 つの機能を探索するつもり。

  • データベース ビューに対してクエリを実行
  • 「定義クエリ」と呼ばれるもう 1 つの新しい機能
  • エンティティ型以外に、FromSql クエリの結果をキャプチャ

重要なクエリの種類には、クエリの種類として、型を認識する必要がある DbContext ModelBuilder ことができます。コンテキストまたは ModelBuilder.Query メソッドを使用して、DbQuery プロパティを作成して操作を行います。新しいは両方ともです。

EF または EF Core は、まったく使用した、ある場合を使用すると、クエリを実行して、DbContext から特定の種類のエンティティを更新する EF クラスの DbSet に慣れておく必要があります。DbQuery は、DbSet、エンティティ型以外をラップし、ビューおよびテーブルに対して読み取り専用のクエリを実行することができますとよく似ています。DbQuery にラップされたこれらの型は、クエリの型。

DbQuery の EF Core の表記規則は、EF Core は、マップ先のデータベース オブジェクトの名前と一致する DbQuery プロパティの名前を DbSet に似ています。

2 つの点の把握しておく必要がありますがマッピングに基づいて、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; }
}

パブリケーションを管理するのには、3 つのエンティティの単純なモデルを使用しています。Magazine、記事、および著者です。

雑誌、記事、作成者のテーブルだけでなく、データベースの名前と作成者が執筆した記事の数を返すように定義されている 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 がこのクエリの種類を理解しているために、EF Core に喜んで協力して、AuthorArticleCount クラスなります。書き込み、データベース ビューに対してクエリを実行するには、これを使用できます。

たとえば、この単純な LINQ クエリ。

var results=_context.AuthorArticleCounts.ToList();

SQLite データベースに送信するのには、次の SQL になります。

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

ように、結果は一連の AuthorArticleCount オブジェクト、図 2します。

1 対 1 のクエリの結果
1 対 1 のクエリの結果を図 2

され、クエリの実行に使用されるコンテキストの ChangeTracker はこれらのオブジェクトをまったく認識できません。

これより良い経験実装よりも過去 EF Core と Entity Framework をデータベース ビューは、テーブルと同様に扱われますが、その結果は、エンティティをさせる必要があるおよび誤って変更トラッカーを追跡しないように注意する必要がありました。

DbContext クラスでの DbQuery 事前に定義せずにクエリを実行することになります。DbSet これを実現できます同様に、DbContext インスタンスのセット メソッドを使用します。DbQuery、としてクエリを記述することができます。

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

クエリ型のマッピングを構成します。

すべての規則に従っているために、この DbQuery は簡単にしていました。Dbset とそのエンティティは、EF Core 規則に従っていない、ときに、OnModelCreating メソッドで正しいマッピングを指定するのに Fluent API や data annotations を使用します。ModelBuilder のエンティティのメソッドの使用に影響するモデルのエンティティを識別することによって開始します。DbSet には、DbQuery で子メンバーが得られる、同様エンティティ メソッドは新しい子メンバーもあります。クエリを実行します。新しい表示メソッド (ToTable メソッドに似ています) を使用して、別の名前のビューを AuthorArticleCounts DbQuery をポイントするクエリ メソッドを使用する例を次に示します。

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

クエリ < T > メソッドは、QueryTypeBuilder オブジェクトを返します。表示は、拡張メソッドです。クエリの種類を調整するときに使用できるメソッドを数多くあります。QueryTypeBuilder は、EntityTypeBuilder メソッドのサブセットがあります。HasAnnotation、HasBaseType、HasOne、HasQueryFilter、IgnoreProperty および UsePropertyAccessMode します。表示およびことをお勧めするクエリの種類のドキュメント内にヒントとして強調表示されている ToTable に関する優れた説明 (bit.ly/2kmQhV8)。

リレーションシップでクエリの種類

HasOne メソッドに注目してください。別の種類のクエリではありませんが、エンティティと一対一または一対多のリレーションシップで相互に依存する (「子」とも呼ばれます) を有効にするクエリの種類のことができます。クエリの種類がないこと、リレーションシップ内のエンティティとしてほぼ柔軟な個人的妥当であるにも注意してください。特定の方法でリレーションシップを設定する必要があります。

作成者のエンティティと AuthorArticleCount の間の一対一のリレーションシップから始めます。これを実装するための最も重要な規則は次のとおりです。

  • クエリの種類、リレーションシップの他方の end にナビゲーション プロパティがあります。
  • エンティティは、クエリの型にナビゲーション プロパティを含めることはできません。

後者の場合、AuthorArticleCount プロパティの作成者を追加した場合、コンテキストと思われる、AuthorArticleCount はエンティティになり、モデル ビルダーは失敗します。

2 つの変更を使って、モデルは機能強化されました。

最初に、作成者のプロパティを含める AuthorArticleCount を変更しました。

public Author Author { get; private set; }

[作成者と AuthorArticleCount 間の一対一のマッピングを追加します。

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

これで LINQ クエリを一括で読み込み、作成者のナビゲーション プロパティを実行できる例。

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

図 3 にその結果を示します。

一括読み込みのクエリの種類と、エンティティ間の一対一のリレーションシップの結果
一括読み込みのクエリの種類と、エンティティ間の一対一のリレーションシップの結果を図 3

一対多リレーションシップでクエリの種類

一対多リレーションシップでは、クエリの種類である依存 end、プリンシパル (親とも呼ばれます) ことも必要です。これを参照するには、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 があることができます、Magazine エンティティとの関係が定義されていることを指定します。

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

データのグラフを取得するクエリを実行することができます。もう一度、Include メソッドを使用します。その ArticleViews で雑誌のグラフに対してクエリを実行できず、これらのグラフを参照してください、Magazine クラスでクエリの種類への参照をないことに注意してください。のみに移動できます ArticleView から Magazine、これは、実行できるクエリの種類。

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

クエリ メソッドにクエリで使用しているため、DbQuery を作成していないはことに注意してください。

見られる、HasOne の API ドキュメントbit.ly/2Im8UqR、このメソッドを使用してについて詳しく説明します。

新しい定義のクエリ機能

表示、だけでなく EntityTypeBuilder、上に存在しない QueryTypeBuilder で他の 1 つの新しいメソッドがあるし、照会です。DbContext で直接クエリを定義することができますを照会し、このようなクエリは「定義クエリ」と呼ばれます LINQ クエリを作成し、定義クエリを作成するときでも FromSql を使用できます。EF チームの Andrew Peters を説明する"を照会の 1 つの用途は、メモリ内プロバイダーをテストするためです。アプリをデータベース ビューを使用している場合は、インメモリを対象とする場合にのみ使用される照会定義もできます。この方法でテスト用データベース ビューをシミュレートすることができます。"

開始するには、クエリの結果を処理する 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;}
}

Magazine のエンティティをクエリする 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、2 つのアーティクルと、MSDN magazine の 1 つの一意な作成者が、2 つの一意の作成者、新規 Yorker の 2 つの記事を正しく表示します。

定義クエリを使用したクエリの結果
定義クエリを使用したクエリの結果が 4 つの図します。

エンティティ型以外に、FromSql 結果をキャプチャします。

Entity Framework の以前のバージョンでは、SQL そのものを実行し、ランダムな型では、その結果をキャプチャすることでした。この種類のクエリの種類に協力してくれたのクエリを実行することに近いいます。EF Core 2.1 を使用して生 SQL クエリの結果をキャプチャするタイプは、エンティティにする必要はありませんが、クエリの種類として、モデルによって既知であるがまだ。

これになります (多くの制限事項の) でできることを匿名型を返す、1 つの例外があります。この制限付きサポートもにも役立ちます、価値を認識するようにします。FromSql と生 SQL クエリを使用して、匿名型を返すクエリを次に示します。

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

エンティティのクエリを実行して、匿名型を返すことは、投影には、DbSet によって表される型の主キーが含まれている場合にのみ機能します。著者 Id を含むしなかった場合、ランタイム エラーは、プロジェクション内に存在しない著者の Id の不満の。または、コンテキストで開始した場合。Magazines.FromSql は先ほど説明した同じクエリを使用して、実行時エラーが利用できない MagazineId に関する文句を言うとします。

この機能を効率的に使用では、型を事前に定義し、DbContext が、DbQuery を定義または OnModelCreating で modelBuilder.Query の種類を指定して、その型の対応を確認します。[クエリを実行して結果をキャプチャする FromSql を使用できます。不自然な例については、またはおそらくさらのいくつかの例を既に使用したよりも不自然とする必要がありますと新しいクラス、エンティティまたはマイ PublicationsContext の一部でない発行元です。

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

読み取り専用のクラスは、パブリッシャーのデータを維持する別のアプリケーションもが。

DbQuery < Publisher > 自分のコンテキストでパブリッシャーをという名前を作成したとするを使用して生 SQL クエリを実行するようになりました。

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

生 SQL では、呼び出しストアド プロシージャを実行することもできます。結果のスキーマが (この例では、パブリッシャー) で型を一致としてもパラメーターを渡しているを行うことができます。

EF Core で、ポーランド語を配置します。

保持してきた、実稼働可能になるまで、EF Core を使用して、時間はついにします。EF Core 2.0 が飛躍的に機能および機能とバージョン 2.1 が製品を実際のポーランド語を配置する機能が含まれています。EF Core に表示される EF6 の機能の待機は、EF チームだけがコピーされていない古い実装がよりスマートより高機能の実装を見つかったファクトする要因にされています。クエリの種類は、この好例ビューと未加工の SQL は、Entity Framework の以前のバージョンでサポートされた方法と比較します。EF Core ドキュメントの「新規の EF Core 2.1 機能」セクションを参照して、EF Core 2.1 で他の新しい機能を確認してくださいbit.ly/2IhyHQRします。


Julie Lerman は、バーモント ヒルズ在住の Microsoft Regional Director、Microsoft MVP、ソフトウェア チームの指導者、およびコンサルタントです。世界中のユーザー グループやカンファレンスで、データ アクセスなどのトピックについてプレゼンテーションを行っています。彼女のブログは thedatafarm.com/blog (英語) で、彼女は O'Reilly Media から出版されている『Programming Entity Framework』(2010 年) および『Code First』版 (2011 年)、『DbContext』版 (2012 年) を執筆しています。彼女の Twitter (@julielerman、英語) をフォローして、juliel.me/PS-Videos (英語) で彼女の Pluralsight コースをご覧ください。

この記事のレビューに協力してくれたマイクロソフト技術スタッフの Andrew Peters
Andrew Peters は、Entity Framework チームの主席エンジニアです。チームの 9 年の中には、Andrew は、LINQ、Code First では、やなど、移行の間で、携わってされ、EF Core のアーキテクチャの潜在顧客の 1 つでした。余暇には、Andrew は、料理、若い、家族と時間を費やすに、ギター、ゲームを楽しんでいます。


この記事について MSDN マガジン フォーラムで議論する