Open棟梁Project - マイクロソフト系技術情報 Wiki
.NET Framework 3.5 SP1で追加されたデータベースアクセステクノロジー
Entity Frameworkは、インピーダンス・ミスマッチ問題を解決するため、
エンティティを定義し、エンティティ経由でデータベースへアクセスするための手段を提供する技術。
CSDL、SSDL、および MSL 仕様
http://msdn.microsoft.com/ja-jp/library/vstudio/bb399604.aspx
CSDL(Conceptual Schema Definition Language:概念スキーマ定義言語)
概念スキーマ(概念モデル)
MSL(Mapping Schema Language:マッピング・スキーマ言語)
CSDLとSSDL(モデル間)のマッピング
SSDL(Storage Schema Definition Language:ストア・スキーマ定義言語)
ストレージ・スキーマ(ストレージ モデル)
モデル(EDM)からDBMSのスキーマを生成する方法
- 多対多関係の実現
- EDMからデータベースの自動生成
http://www.atmarkit.co.jp/fdotnet/ef4basic/ef4basic02/ef4basic02_02.html- Entity Frameworkで自動生成されるクラス
- Entity Frameworkでのデータ保存/取得サンプル
DBMSのスキーマからモデル(EDM)を生成する方法
- データベースからのEDM生成
- ストアド・プロシージャの呼び出し
- 複合型の活用/まとめ
(モデルクラスへのデータ構造の定義が、そのままデータベースのテーブル設計となる)
ここでは、「context」がDbContext?を継承したコンテキストを指している。
サンプルプログラム次第で、context, db, dbContextなどの名称が使用される。
Entityは以下のEntity Statesを持っており、
SaveChanges?()メソッドを呼び出した際に、
コレを更新系SQLに変えて実行すると言う、ある種、
RowState? + TableAdapter的な仕組みで動作している。
using (var context = new XXXXXContext()) { // YYYYY Entity の Statesが // Unchanged状態→Added状態へ。 context.YYYYYs.Add(new YYYYY { プロパティ名1 = 値1, プロパティ名2 = 値2, }); // SaveChanges→Added状態の // YYYYY EntityがInsert文に替えられる。 context.SaveChanges(); }
using (var context = new XXXXXContext()) { var yyyyy = context.YYYYYs.Single(x => x.Name == "hogehoge"); yyyyy.Name = "Aiueo"; context.SaveChanges(); }
using (var context = new XXXXXContext()) { var yyyyy = context.YYYYYs.Single(x => x.Name == "hogehoge"); context.YYYYYs.Remove(yyyyy); context.SaveChanges(); }
using (var context = new XXXXXContext()) { var toRemoveYyyyy = new YYYYY { Id = 1 }; context.YYYYYs.Attach(toRemoveYyyyy); context.YYYYYs.Remove(toRemoveYyyyy); context.SaveChanges(); }
LINQは遅延評価なので、結果が必要になるまではSql文が発行されない。
ToArray()メソッドや、Load()メソッドを使うと、
即時実行されて結果をメモリに起こす事ができる。
オブジェクト参照によりSQLが実行される。
using (var context = new XXXXXContext()) { foreach (var YYYYY in context.YYYYYs) { Console.WriteLine(YYYYY.Name); } }
context.YYYYYs.Single(x => x.name == "hogehoge");
context.YYYYYs.Single(x => x.name == "hogehoge");
以下の様な感じ。
var YYYYYs = context.YYYYYs.ToArray(); YYYYYs.Where(x => x.Name == "hogehoge")
context.YYYYYs.Load() context.YYYYYs.Local.OrderBy(x => x.Name);
詳しくは、LINQ to Objectを参照。
以下の様な感じ。
context.YYYYYs.Where(x => x.Id == "1"); context.YYYYYs.Where(x => x.Name == "hogehoge").ToArray();
詳しくは、次章を参照。
全体的に実行されるSQLがブラックボックスで性能を意識し難い。
LINQ to Entities, QueryBuilder?, Entity SQL
全体的に、
から
などがブラックボックス化されているため、
Entity Framework自体の仕様に精通していないと、
ハイパフォーマンスな実装をすることができない。
という問題がある。
foreachでデータアクセスした場合など、
検索SQLが検索キーや射影の列名を指定しないので性能的に問題になる。
以下の様な手段により、処理対象のEntityをメモリに起こしてしまう。
この場合、ToArray?()メソッドを使って、はじめに結果を確定させる。
var YYYYYs = context.YYYYYs.ToArray();
この場合、Load()メソッドを使って、DbContext?内にデータをキャッシュさせる。
context.YYYYYs.Load();
この後、context.YYYYYsにアクセスしてもSQLは実行されない。
となる。
処理される場所だけでなく、処理結果が異なることがある。
context.YYYYYs.OrberBy(x => x.Name).ToArray()
context.YYYYYs.ToArray().OrderBy(x => x.Name)
DBMSの照合順序などの関係により、
処理される場所によって、ソート(OrberBy?)順が異なるためである。
AsNoTracking?()メソッドでCollectionを取得すると、
Entity Statesのトラッキングをしなくなる。
var YYYYYs = context.YYYYYs.AsNoTracking().ToArray();
これにより、使用するメモリ量を削減できる。
コードファーストのデータモデルクラスの変更をもとに、
既存のデータを残したままデータベースのテーブルを変更する機能。
コードファーストでは規約に基づいてEntityとDatabaseを紐付ける。
項番 | 属性名 | 説明 |
1 | Table | EntityとTable間のマッピング |
2 | Columnj | EntityのPropertyとTableのColumn間のマッピング |
エンティティ間の関連(アソシエーション)を表す。
基幹系システムでは以下の理由でミスマッチと判断されることが多い。
SQLが、LINQ to Entityのエンジンに生成される形であり、
また、内部実装とその動作がブラックボックスになっているため(※1)
それらが明確にならないと設計、チューニング、問題分析などが困難。
従って(特に日本の)エンタープライズ・アプリケーションでは敬遠されている。
これは、JavaのJava8でJPAでHibernateでJinqが敬遠されるのと≒。