連載:Entity Framework 4.1入門 第3回 Fluent APIとDbContextの機能 WINGSプロジェクト 土井 毅(監修:山田 祥寛)2011/08/16 |
|
Page1
Page2
|
■DbContextクラスとDbSetクラスの使用方法
EF 4.1で導入されたDbContextは、データベースに接続するための軽量のコンテキスト・クラスであり、EF 4まで使用されていたObjectContextクラスの機能のうち、頻繁に使用されるものが実装されている。また、DbContextクラスに合わせて導入された、エンティティの集合を表すDbSetクラスも同様に、EF 4までのObjectSetクラスのサブセットとなっている。
ここでは、DbContextクラスとDbSetクラスによる基本的なクエリ方法と、エンティティの変更履歴管理の方法および同時実行制御について解説する。
●基本的なクエリの方法
DbContextでのクエリには、いくつかの方法がある。
- DbSet型のプロパティに対するLINQ(LINQ to Entities)
- DbSetクラスのFindメソッド
1はこれまでのサンプルでも使用してきたように、DbSet型のプロパティに対し、LINQを使ってクエリを行うものである。LINQの使用方法は対象とするデータの種類に依存しないため、これまでLINQを使ってきた開発者であれば、違和感なくLINQ to Entitiesを使用できるだろう。
ここでは2のDbSetクラスのFindメソッドによるクエリ方法について示す。
DbSetクラスのFindメソッドは、主キーを指定し、対応する1つのエンティティを取得するメソッドである。複合主キーを持つエンティティの場合、複数のフィールドを順番に並べることでクエリを行える。
リスト4は、Findメソッドの使用例である。前述の複合主キーを持つCompositeKeyEntitiesのFindメソッドで複数のキーを指定して検索していることに注目してほしい。
|
||
リスト4 Findメソッドを使った主キーによる検索(上:Program.cs、下:Module1.vb) |
実行結果は図8のようになる。
図8 Findメソッドの実行結果 |
Findメソッドのほか、DbSetクラスには表2のようなメソッドが準備されている。
メソッド名 | 意味 |
Add(Object entity) | エンティティをコレクションに追加する |
Create() | 新しいエンティティを作成する。作成したエンティティはコレクションには追加されていないことに注意 |
Remove(Object entity) | エンティティをコレクションから削除する |
SqlQuery(string sql,params Object[] parameters) | エンティティを返すパラメータ付きSQLを実行する |
表2 DbSetクラスのメソッド |
●変更履歴管理
変更履歴管理とは、特定のエンティティがデータベースから読み込んだ状態のままか、あるいは変更/削除/追加されたものか、といった情報を管理することである。EF 4において、自己追跡エンティティという機能が追加され、POCOベースのエンティティ・クラスを基に、変更履歴の自動的な記録が可能となった。
ただし、EF 4でエンティティの変更履歴管理を行うためには、自己追跡エンティティという、POCOベースではあるものの、特別な機能を持つクラスでエンティティを定義する必要があった。EF 4での変更履歴管理については、「連載:ADO.NET Entity Framework入門 第6回 EF4によるN層アーキテクチャと自己追跡エンティティ【前編】」を参照してほしい。
それに対し、EF 4.1のDbContextクラスでは、任意のエンティティ・クラスについて、変更履歴の管理が可能となった。
使用方法はシンプルで、DbContextクラスのEntryメソッドで取得できるDbEntityEntryオブジェクトから、エンティティの変更情報を取得できる。DbEntityEntryオブジェクトのStateプロパティはそのエンティティの状態を表す(表2)。
状態 | 意味 |
Detached | エンティティは作成直後で、まだコレクションに追加されていない |
Unchanged | エンティティは変更されていない。SaveChangesメソッドで変更を反映した後もこの状態になる |
Added | エンティティはコレクションに追加されたが、まだ変更は反映されていない |
Deleted | エンティティは削除された |
Modified | エンティティは変更された |
表2 Stateプロパティの意味 |
また、DbEntityEntryオブジェクトのPropertyメソッドから取得できるDbPropertyEntryオブジェクトでは、表3のようなプロパティにより、特定のプロパティの変更前/変更後の値、および変更状態を取得できる。
プロパティ | 意味 |
CurrentValue | 変更前のプロパティの値 |
OriginalValue | 変更後のプロパティの値 |
IsModified | プロパティの値が変更されたかどうか |
表3 DbPropertyEntryクラスのプロパティ |
変更履歴管理はデフォルトで有効になっており、便利な機能であるが、大量のエンティティを追加する場合などは、処理のオーバーヘッドを避けるため明示的に変更履歴管理を無効化することが望ましい。
変更履歴管理の有効/無効はDbContextオブジェクトのConfiguration.AutoDetectChangesEnabledプロパティで指定できる。このプロパティで履歴管理を無効化すると、エンティティのStateプロパティや、プロパティのIsModifiedプロパティが正しく動作しなくなる。ただし、変更履歴管理を無効にしても、プロパティごとのCurrentValueプロパティとOriginalValueプロパティは異なる値を保持し続ける。
リスト5は、変更履歴管理により、エンティティの追加や変更内容を取得するサンプルである。
|
||
リスト5 変更履歴管理により、エンティティの追加や変更内容を取得するサンプル(上:Program.cs、下:Module1.vb) |
●楽観的同時実行制御
同時実行制御とは、データベースに更新をかける際に、書き込みの競合を避けるための処理のことである。同時実行制御を適切に行わない場合、図9のように書き込んだはずのデータが失われてしまいかねない。同時実行制御の詳細については、「できるエンジニアになる! ちょい上DB術・基礎編 第2回 【DB概論】DBMSに求められるもの(1)排他制御とACID属性」などを参照してほしい。
図9 同時実行制御を行わない場合のデータ損失 |
EF 4.1では、簡単に楽観的(オプティミスティック)同時実行制御を行うための仕組みが用意されている。楽観的同時実行制御とは、図10のようにデータの書き込み時に、自分が読み込んだ時のデータと、データベース上のデータを比較し、自分が読み込んで以降、誰も変更していないかどうかを確認する手法である。楽観的同時実行制御により、自分以外のユーザーの更新を適切に検出できるようになり、データの損失を避けることができる。
図10 楽観的同時実行制御の仕組み |
EF 4.1では、リスト6のようにTimestampというアノテーションにより、データベースのレコードのバージョンを表すプロパティを表現できる。Timestampアノテーションを付加したプロパティは、SQL Server上ではrowversion型(以前のTimestamp型)のフィールドとなり、データベース側でレコードの更新ごとに自動的にバージョンを表す数値が格納される。このフィールドを使うことで、自分がそのレコードを読み込んで以降、変更されていないかどうかを確認できる。
|
||
リスト6 Timestampアノテーション(上:Item.cs、下:Item.vb) |
EF 4.1では、Timestampアノテーションが付加されたプロパティがある場合、DbContextクラスのSaveChangesメソッドを呼び出した際に、そのプロパティの値とデータベース上の値の比較が行われる。もし異なっている場合(=自分が読み込んで以降、誰かが書き込んだ場合)には、DbUpdateConcurrencyException例外(System.Data.Entity.Infrastructure名前空間)が発生し、書き込みは行われない。
リスト7は楽観的同時実行制御のサンプルである。
|
||
リスト7 楽観的同時実行制御のサンプル(上:Program.cs、下:Module1.vb) |
ビルド後、以下の手順で同時実行制御のテストを行える。
-
コマンド・プロンプトから「bin\Debug\EFCodeFirstSampleCS.exe」(VBは「EFCodeFirstSampleVB.exe」)を実行(プロセスA)
-
別のコマンド・プロンプトから同じ実行ファイルを実行(プロセスB):
この時点で、両プロセスで同じレコードが読み込まれ、両方ともプログラム中で書き換えられているが、データベースには反映されていない。 -
プロセスAでキー入力:
これにより、プロセスAがSaveChangesメソッドでデータベースに変更を反映する。保存は成功し、Timestampフィールドの値は更新される。 -
プロセスBでキー入力:
プロセスBもSaveChangesメソッドで保存しようとするが、2の時点で読み込んだTimestampフィールドの値は、3で書き換えられたため、楽観的同時実行制御により、保存は失敗し、DbUpdateConcurrencyException例外が発生する。
楽観的同時実行制御はEF 4においてもサポートされていたが、このサンプルからも分かるとおり、EF 4.1ではTimestampアノテーションにより、簡潔な記述で行えるようになっている。
■まとめ
全3回のシリーズで、EF 4.1の新機能について解説してきた。EF 4.1の目玉であるコード・ファースト機能は、これまでになくスピーディなデータベース開発を可能にしてくれる。また、今回解説したDbContextクラスの新機能である、自動的な変更履歴管理と楽観的同時実行制御は、コード・ファースト以外でも使用可能で、実際のアプリケーションにおいて有用な機能である。EF 4までの記述よりもずっとシンプルに機能を使えるため、ぜひ活用してほしい。
マイクロソフトの一押しフレームワークであるASP.NET MVCが、Entity Framework 4.1との強力な連携機能を搭載していることからも分かるように、Entity Frameworkは今後も重要なデータ・アクセス技術と位置付けられるだろう。本連載がEntity Framework活用の一助になれば幸いである。
INDEX | ||
[連載]Entity Framework 4.1によるコード・ファースト開発 | ||
第3回 Fluent APIとDbContextの機能 | ||
1.外部からデータベース構造を設定するFluent API | ||
2.DbContext、DbSetクラスの使用方法 | ||
「連載:Entity Framework 4.1入門」 |
- 第2回 簡潔なコーディングのために (2017/7/26)
ラムダ式で記述できるメンバの増加、throw式、out変数、タプルなど、C# 7には以前よりもコードを簡潔に記述できるような機能が導入されている - 第1回 Visual Studio Codeデバッグの基礎知識 (2017/7/21)
Node.jsプログラムをデバッグしながら、Visual Studio Codeに統合されているデバッグ機能の基本の「キ」をマスターしよう - 第1回 明瞭なコーディングのために (2017/7/19)
C# 7で追加された新機能の中から、「数値リテラル構文の改善」と「ローカル関数」を紹介する。これらは分かりやすいコードを記述するのに使える - Presentation Translator (2017/7/18)
Presentation TranslatorはPowerPoint用のアドイン。プレゼンテーション時の字幕の付加や、多言語での質疑応答、スライドの翻訳を行える
|
|