この記事は機械翻訳されたものです。

データ ポイント

私のお気に入りのいくつかの. エンティティ フレームワーク 4.2 DbContext で

Julie Lerman

Julie Lermanエンティティ フレームワーク 4.1 2011 年初頭にリリースする前に、開発者にそのパッケージに与えられたの半分だけに焦点を当てていた。最初のコードします。 コードは、まずドメイン クラスとコードの最初の構成を使用してエンティティ データ モデル、ビジュアル デザイナーを使用してモデルを定義するしたくない開発者のすばらしい代わりを表現できます。 しかし、すべてのビットは、エンティティ フレームワーク (EF) をこれらのクラスとコード最初定義モデルを使用するためのサンプル コードの EF 4.1 で来た別の非常に重要な機能によって駆動されます。DbContext クラス。

ObjectContext クラスは、EF API で、マイクロソフトのコアの一部です。フレームワーク 4 をネットし、クエリを実行、変更の追跡と、データベースを更新することができます、クラス モデルを表す、厳密に型指定されたクラスを使用しています。 ラッパーのほとんどを一般公開 ObjectContext に ObjectContext の機能を使用し同様にいくつかの簡単な「ショートカット」頻繁に使用される ObjectContext を直接コードに複雑なタスクを提供 DbContext クラスもんじゃです。

それは私の指導とマイクロソフトで DbContext 最初 EF を使用して新しいプロジェクトを開始時に検討する必要があることの。 時折、ObjectContext クラスを提供するより詳細なロジックのいくつかにアクセスする必要がある場合は、DbContext インスタンスからその基になる ObjectContext に取得するフックです。

var objectContext = (myDbContextInstance as IObjectContextAdapter).ObjectContext

直接 ObjectContext 機能の頻繁に使用する必要があります仕事をやっているよ知っている場合は、使用したいと思う可能性があります DbContext ではなく。 しかし、一般には、EF チーム、DbContext いくつかの理由を使用してから禁止している限り、ObjectContext を直接使用しないことを推奨します。

このガイダンスとは、新しいプロジェクトの警告を追加します。 DbContext API を使用すると、新しいスリムとスマートな DbContext クラス、だけも同様に改善の DbSet と DbQuery クラス (ObjectSet、ObjectQuery に対応) を取得します。

私は、DbContext の大ファンが、その機能のいくつかの私のお気に入りの小さなペットとなっています。

DbSet.Find

新しい api のいずれかの DbSet.Find です。 これは、一般的なパターンの開発者用データへのアクセスをできます。その主キーに基づいて、単一のオブジェクトを取得します。

ObjectContext では、完全なクエリを作成し、SingleOrDefault など、LINQ メソッドを使用してクエリを実行する必要があります。

それのようになります。

var partyHatQuery = from p in context.PartyHats where p.Id == 3 select p;
var partyHatInstance = partyHatQuery.SingleOrDefault();

より効率的に LINQ メソッド、ラムダを書くことができます。

var partyHatInstance = context.PartyHats.SingleOrDefault(p => p.Id == 3);

どのくらいの頻度この単純なタスクを実行するクエリを実行しているか? あなたもこのコード簡単な方法で分離が可能性があります。

これは EF チームを DbContext API にしたものです。 DbContext を使用する場合、PartyHats は、DbSet <PartyHat> になるし、すぐに、同じクエリを実行する、DbSet.Find メソッドを使用することができます。

context.PartyHats.Find(3)

このメソッドが指定した値は、キーの値を検索しているクラスを想定しています — この場合は、PartyHat。 EF は、実行 SingleOrDefault クエリ Id が渡された値に等しいデータを捜してあなたに代わって — この場合は、3。 おそらく、変数には、実際の値ではなく、通過されます。

クエリを達成することはできません、DbSet.Find メソッドのもう一つの利点です。 Find メソッドは最初メモリ コンテキストによって追跡されている、一致するオブジェクトになります。 ある場合は、[EF データベースを照会する気にしません。 これは、オブジェクト インスタンスは、既にメモリにある場合のみ、クエリの結果は捨てる、データベースにクエリを実行するよりもはるかに効率的です — 多くの開発者が気付かないトリガーがデータベースに無駄な旅行。

DbSet.Find 複合キーを使用することもできます。 検索のシグネチャのパラメーター配列を使用すると、1 つのオブジェクトは。 そのため、キーを構成する値を表す値のリストで渡すことができます。

DbSet.Local

EF で作業する場合、私は頻繁に自分自身何か既にメモリで、コンテキストによって追跡されていたオブジェクトをしたいが見つかりました。 このロジックのための典型的な場所、SaveChanges オーバーライド SavingChanges メソッド、ここでいくつかの検証を実行するでか。 (新しい検証 DbContext と共に使用できる API におかげで、私はこのロジックの多くを削減することがしてきた。 しかし、私はこの列での検証を説明しません。)

ObjectContext それを追跡している、オブジェクトを検出する手段が、これを行うには、API のロジックを簡単に見つけることも簡単にコードです。 実際には、私の本、「Entity Framework のプログラミング」(オライリー メディア、2010)、このタスク簡単にして、より柔軟なのに 4 つのメソッドの拡張機能セットを書いた。

一般に、ただし、開発者コンテキストに、LINQ to Entities クエリを実行してコンテキストが既に追跡はこれらのオブジェクトとの相互作用の違いに気付いていません。 たとえば、多くの開発者は、クエリを使用してデータを取得します、何今クエリによって管理されているのロジックを実行しようとして、コードを見てきました。

var balloons = context.Balloons.Where(b => b.Size == "L").ToList();
 var balloonCount = context.Balloons.Count();

実際には、これら 2 つの独立したクエリです。 コードの 2 行目はデータベースを別のクエリを実行し、すべての風船の数を返します。 通常、開発者の意図した結果の数を取得するだった — つまり、吹き出し。カウントします。

変数へのアクセスを持っていないが、まだ、ObjectContext を追跡しているどのように多くのバルーン オブジェクトを検索する場合を確認する方法が簡単ではありません。ObjectContext 公開、ObjectState­GetObjectStateEntries と呼ばれるメソッドを持つマネージャー。 このメソッドでは、それを返すには、エントリを知っているので、1 つまたは複数の EntityState 列挙 (たとえば、追加、本などで) に渡す必要があります。 結果がクエリが、フィルタ リングは複雑であるし、もない、エンティティ オブジェクトの状態情報を表す ObjectStateEntry インスタンスが返されます。

つまり、私の拡張メソッドを使用せず、メモリで、風船の数を取得するコード次のように見えます。

objectContext.ObjectStateManager
 .GetObjectStateEntries(EntityState.Added |
                        EntityState.Modified | EntityState.Unchanged)
 .Where(e => e.Entity is Balloon).Count();

これらのバルーン オブジェクトだけでなく、ObjectStateEntry のインスタンスをキャプチャする場合は、ObjectStateEntry.Entity 型として風船を返すいくつかの鋳造を追加する必要があります。

objectContext.ObjectStateManager
 .GetObjectStateEntries(EntityState.Added |
                        EntityState.Modified | EntityState.Unchanged)
 .Where(e => e.Entity is Balloon)
 .Select(e => e.Entity as Balloon);

このコードを見ることとしてほとんど私は、新しいプロパティの DbSet.Local に感謝することがあります。

DbSet.Local を使用して、すべての履歴のバルーン インスタンスからコンテキストを取得する、単に呼び出すことができます。

context.Balloons.Local;

「ローカル」の 2 つの利点を提供、ObservableCollection をを返します。 最初のクエリは、どんなローカルにキャッシュされた風船のサブセットを返すことができますようにすることです。 2 番目、コードだ (またはデータ バインド コントロールなどのコンポーネント) することができますを聞くし、追加または、キャッシュから削除されるオブジェクトに反応です。

検出のプロパティと、減少したコード以外は、DbSet.Local と GetObjectStateEntries を使用して 2 つ他顕著な違いです。 GetObjectStateEntries エントリの彼らが表すオブジェクトの種類にかかわらず返しますローカルが、特定の DbSet からのみオブジェクトを返すことです。 他の違いは、ローカル コンテキストを知っているオブジェクトが削除済みとしてマークされますが返されないことです。 GetObjectStateEntries では、追加、変更、変更なし、削除済みのオブジェクトにメソッドを提供するパラメーター リストで指定したへのアクセスがあります。

NoTracking LINQ クエリ

クライアントのパフォーマンスを議論するとき、しばしばコンテキストによって追跡する必要のないデータを返す EF 機能の活用お勧め。 たとえば、ドロップダウンの選択リストに指定する必要があるデータがあります。 決して必要は、そのデータを変更、はるかに少ないがデータベースに保持します。 したがって、パフォーマンスを避けるためにスマートです EF ObjectStateEntry インスタンスは追跡は、それらのオブジェクトに加えられた変更を認識するコンテキストを強制するだけでなく、各オブジェクトの作成がヒット。

ObjectContext を NoTracking サポート LINQ to Entities クエリからではなく、ObjectQuery クラスを通じてのみ利用可能です。

(コンテキストと呼ばれます)、ObjectContext を使用して、NoTracking クエリの典型的な例です。

string entitySQL = " SELECT p, p.Filling " +
                           "FROM PartyContext.Pinatas AS p " +
                           "WHERE p.Filling.Description='Candy'";
var query=context.CreateQuery<DbDataRecord>(entitySQL);
query.MergeOption = System.Data.Objects.MergeOption.NoTracking;
var pinatasWithFilling=query.ToList();

取得したピニャータと詰め物のメモリ内のオブジェクトがそれらの知識のコンテキストはありません。

しかし、あなた、IQueryable、いない、ObjectQuery を返します、エンティティのクエリに次の LINQ を使用する場合がない MergeOption プロパティ。

context.Pinatas.Include("Filling")
  .Where(p=>p.Filling.Description=="Candy")

1 つのソリューションは LINQ クエリが ObjectQuery にキャストし、MergeOption を設定することです。 これは明白ではないだけでなくも不格好です。

これを認識し、EF チーム、あなたのパーティーのケーキを有し、それも、新しい AsNoTracking 拡張メソッド DbContext API の一部である IQueryables を食べるようにする方法が見つかりました。 今私は LINQ クエリにタックそれすることができます。

context.Pinatas.Include("Filling")
  .Where(p=>p.Filling.Description=="Candy")
  .AsNoTracking();

これは、一連の Pinatas と詰め物のコンテキストでは無視されますが返されます。 EF wastethe 努力 DbEntityEntry オブジェクト (ObjectStateEntry の DbContext API バージョン) の各オブジェクトをインスタンス化することはありません。 また、DetectChanges が呼び出されたときにこれらのオブジェクトを検査するには、コンテキストを強制、努力を無駄にします。

簡単なコードであり、非常に IntelliSense を通じて検出。

ケーキのアイシング

これら 3 つの機能 — ローカルと AsNoTracking を見つける-私は ObjectContext を達成されていないタスクを実行するを有効にしないでください。 しかし、私はそれらを使用するたびに、私を幸せにします。 そう多数がある (、ObjectContext に比べると)、DbContext API を簡単タスクをコーディング、それ私のアプリケーションの開発はかなり合理化しています。 私はまた古い ObjectContext コードに返され、DbContext コード最初のと共にを使用してそれらのアプリケーションでのコードの量を大幅に削減することができたにリファクタリングします。 しかし、私は、EF では密接に慣れていない開発者のために、その機能の多くを検出を取得してそれを実行しているは大きな違いになります。

Julie Lerman*、Microsoft MVP であります。ネットのメンターとバーモント州の丘に住むコンサルタント。 データ アクセスおよび他の Microsoft の彼女の提示を見つけることができます。ユーザー グループと、世界中のカンファレンスでのネットのトピック。彼女のブログで thedatafarm.com/blog 、「Entity Framework のプログラミング」の著者 (2010 年)、「プログラミングのエンティティ フレームワーク。最初のコード」(2011 年)、両方の米オライリー メディア社から。彼女に Twitter に続く twitter.com/julielerman。*

この記事のレビュー、技術スタッフのおかげでに: Arthur Vickers