-
Notifications
You must be signed in to change notification settings - Fork 0
MS_EntityFramework
- 戻る(データアクセスのいろいろ、ADO.NET vs ORM (Entity Framework, Dapper))
- Entity Framework
- Entity Framework Core
.NET Framework 3.5 SP1 で追加されたデータベース アクセス テクノロジー。
- Entity Framework は、
TableAdapterと比べ、より高次の機能を提供し、
高い生産性を誇る RAD ツールです。 - データアクセス部分を隠ぺいするため、
データベースの種類や構造を意識することなくプログラミングできます。 - 反面、実際に発行される SQL 文の構築は Entity Framework に委ねられます。
- このため、チューニングや、柔軟なデータの参照・更新が課題になりやすく、
ミッション クリティカルなエンタープライズ システム開発には適合しないことがあります。
補足(最新化:EF6 と EF Core): 本ページが扱っているのは
**EF6(Entity Framework 6.x)**である。現在の位置付けは以下。
EF6 EF Core 対象 .NET Framework(.NET Core 3.0 以降でも動作) .NET(クロスプラットフォーム) 開発 保守のみ(新機能なし) 現行。年次でメジャー更新 EDMX / デザイナ あり なし 開発スタイル モデル / DB / コード ファースト Code First と scaffold のみ 名前空間 System.Data.EntityMicrosoft.EntityFrameworkCore新規開発では EF Core を選ぶ。
本ページの EDM / CSDL / MSL / SSDL に関する記述は
EF6 固有であり、EF Core には該当する概念が存在しない。
Entity Framework は、インピーダンス・ミスマッチ問題を解決するため、
エンティティを定義し、エンティティ経由でデータベースへアクセスするための手段を提供する技術。
-
概念モデルである Entity Data Model(EDM) を開発者が柔軟にモデリング可能。
RDB に対して直接プログラミングする代わりに、EDM に対してプログラミングする。-
これにより、テーブルとオブジェクトを 1 対 1 に対応させる O/R マッパとは異なり、
「結合(Join)」という RDB 固有の事情に振り回されることなく、
より直感的に必要な情報を取得することが可能になる。 -
RDB 側のスキーマ変更(特にテーブルの分割/統合のような変化)に対して耐性がある。
-
-
Entity は ADO.NET 非接続型と同様に、多階層のアプリケーションを開発する場合、
オブジェクトとして渡すことが可能であり DTO(Data Transfer Object) として利用できる。
CSDL、SSDL、および MSL 仕様
https://learn.microsoft.com/ja-jp/dotnet/framework/data/adonet/ef/language-reference/csdl-ssdl-and-msl-specifications
-
概念スキーマ定義言語 (CSDL) <---> マッピング仕様言語 (MSL) <---> ストア スキーマ定義言語 (SSDL) は
XML ベースの言語で、それぞれ概念モデル、モデル間のマッピング、
ストレージ モデルについて記述する。 -
Entity Data Model(EDM) の定義は、Entity Data Model デザイナーにより、
設計時にモデルとマッピングの情報を*.edmxファイルに保存する。 -
Entity Data Model デザイナーは、ビルド時に EDM ファイル(
*.edmx)の情報を使用して、
Entity Framework が実行時に必要とする*.csdl、*.ssdl、および*.mslファイルを作成する。
CSDL(Conceptual Schema Definition Language:概念スキーマ定義言語)
概念スキーマ(概念モデル)
MSL(Mapping Schema Language:マッピング・スキーマ言語)
CSDL と SSDL(モデル間)のマッピング
SSDL(Storage Schema Definition Language:ストア・スキーマ定義言語)
ストレージ・スキーマ(ストレージ モデル)
-
エンタープライズではほぼ、DB ファーストを採用する。
-
単純なテーブル(データストア)しか使用しない
EUC などの世界では、モデルファーストもマッチする可能性がある。
モデル(EDM)から DBMS のスキーマを生成する方法。
- 連載:ADO.NET Entity Framework 入門 - @IT
-
第2回 EDM における多対多関係と Entity Framework でのデータの取得/保存
http://www.atmarkit.co.jp/fdotnet/ef4basic/ef4basic02/ef4basic02_01.html- 多対多関係の実現
- EDM からデータベースの自動生成
http://www.atmarkit.co.jp/fdotnet/ef4basic/ef4basic02/ef4basic02_02.html - Entity Framework で自動生成されるクラス
- Entity Framework でのデータ保存/取得サンプル
-
DBMS のスキーマからモデル(EDM)を生成する方法。
-
連載:ADO.NET Entity Framework 入門 - @IT
第4回 データベースからの Entity Data Model 生成
http://www.atmarkit.co.jp/fdotnet/ef4basic/ef4basic04/ef4basic04_01.html- データベースからの EDM 生成
- ストアド・プロシージャの呼び出し
- 複合型の活用/まとめ
-
ADO.NET Entity Framework 4.1 で登場した機能。
-
Entity へのデータ構造の定義が、そのままデータベースのテーブル設計となる。
-
ASP.NET MVC の Model(Entity)でデータ構造を定義すると、
その定義に従ってデータベースにテーブルが作成される。 - ソースコードのみで完結し、
Entity Framework の Entity Data Model (EDM) などを
明示的に作成する必要がなくなるため、より迅速な開発が可能となる。
-
ASP.NET MVC の Model(Entity)でデータ構造を定義すると、
-
参考
- Entity Framework Code First | densan-labs.net
http://densan-labs.net/tech/codefirst/index.html - 既存のデータベースで EF『コード・ファースト』を使用 (1/4):CodeZine(コードジン)
https://codezine.jp/article/detail/5400 - 第5回 POCO によるエンティティ・クラス - @IT
http://www.atmarkit.co.jp/fdotnet/ef4basic/ef4basic05/ef4basic05_03.html- Entity Framework 4 でコード・ファースト開発 - @IT
http://www.atmarkit.co.jp/fdotnet/scottgublog/20100726codefirst/codefirst.html
- Entity Framework 4 でコード・ファースト開発 - @IT
- Entity Framework Code First | densan-labs.net
補足(最新化:EF Core での対応関係): EF Core には
モデルファースト(デザイナ)が無いため、選択肢は 2 つになる。
元ページの区分 EF Core での対応 モデルファースト 無し DB ファースト dotnet ef dbcontext scaffoldで既存 DB からリバースコードファースト dotnet ef migrations add→dotnet ef database updateエンタープライズで DBA が DB を設計する場合も、
scaffold で生成したコードを起点に手で調整する運用になる。
なお、本番環境へのスキーマ適用はdatabase updateを直接叩かず、
dotnet ef migrations scriptで SQL を出力してレビューするのが安全。
-
- データの挿入、読み出し、更新、削除 | densan-labs.net
http://densan-labs.net/tech/codefirst/adddelete.html
- データの挿入、読み出し、更新、削除 | densan-labs.net
ここでは、「context」が DbContext を継承したコンテキストを指している。
サンプルプログラム次第で、context, db, dbContext などの名称が使用される。
Entity は以下の Entity States を持っており、
-
Unchanged 状態
追跡開始後に変更されていない状態 -
Added 状態
追加された状態。 -
Modified 状態
編集された状態。 -
Deleted 状態
削除された状態。 -
Detached 状態
追跡が開始されていない状態
SaveChanges() メソッドを呼び出した際に、
コレを更新系 SQL に変えて実行すると言う、ある種、
RowState + TableAdapter 的な仕組みで動作している。
補足(変更追跡と更新列): 変更追跡により、
SaveChanges()が生成する
UPDATE文には変更されたプロパティのみが含まれる。
ただし、AsNoTracking()で読んだエンティティや、
別階層から戻ってきた(Detached な)エンティティをUpdate()した場合は
全列が更新対象になる点に注意。
Web API のように「読み取りと更新でリクエストが分かれる」構成では、
この違いが同時実行制御(後述のロストアップデート)に直結する。
補足(同時実行制御): EF には楽観的同時実行制御の仕組みがあり、
更新競合を検出できる。
- SQL Server:
rowversion型の列を用意し、
[Timestamp]属性(またはIsRowVersion())を付ける- 競合時は
DbUpdateConcurrencyExceptionが発生するこれを入れないと、後勝ちでロストアップデートが発生する。
LINQ は遅延評価なので、結果が必要になるまでは SQL 文が発行されない。
ToArray() メソッドや Load() メソッド(Entity Framework の懸念)を使うと、
即時実行されて結果をメモリに起こす事ができる。
オブジェクト参照により SQL が実行される。
using (var context = new XXXXXContext())
{
foreach (var YYYYY in context.YYYYYs)
{
Console.WriteLine(YYYYY.Name);
}
}-
Find()メソッド- 主キーを使用して検索する。
-
DbContextにキャッシュがあれば、それを検索する。 - キャッシュがない or キャッシュ内にデータが無い場合、SQL で検索する。
-
- 主キーを使用して検索する。
-
Single()メソッド- 0 件、複数件の結果が返ったらエラーを返す。
- DBMS の TOP ヒントなどを使用する(
Select Top 2 * From YYYYYs)ので性能はいい。
context.YYYYYs.Single(x => x.name == "hogehoge");
-
SingleOrDefault()メソッド- 取得した結果が 0 件の場合、既定値を返す。1 件の場合、その要素を返す。
- 取得した結果が 0 件 or 1 件以外の結果が返ったらエラーを返す。
- DBMS の TOP ヒントなどを使用する(
Select Top 2 * From YYYYYs)ので性能はいい。
context.YYYYYs.SingleOrDefault(x => x.name == "hogehoge");
-
,etc.
移行メモ(正誤): 元ページの
SingleOrDefault()の例は
コードがSingle()のままだったため、SingleOrDefault()に修正した。
補足(
SingleとFirstの使い分け): 「一意であることを表明したい」なら
Single系、「先頭 1 件でよい」ならFirst系を使う。
First系はSelect Top 1になるため、
Single系(Top 2を取って 2 件目の有無を確認する)より軽い。
一意性が制約で保証されているならFirst系で十分なことが多い。
- 参考
- FirstOrDefault とか Last など単一要素取得の LINQ メソッド - Qiita
http://qiita.com/RyotaMurohoshi/items/0d4cf421e0eb4a9b4765- ElementAt / ElementAtOrDefault
- First / FirstOrDefault
- Single / SingleOrDefault
- FirstOrDefault とか Last など単一要素取得の LINQ メソッド - Qiita
以下の様な感じ。
-
ToArray()メソッドで確定させた結果に対して LINQ を実行する。var YYYYYs = context.YYYYYs.ToArray(); YYYYYs.Where(x => x.Name == "hogehoge")
-
Load()メソッドでキャッシュした後に、
Localプロパティに対して LINQ を実行する。context.YYYYYs.Load() context.YYYYYs.Local.OrderBy(x => x.Name);
詳しくは、LINQを参照。
以下の様な感じ。
context.YYYYYs.Where(x => x.Id == "1");
context.YYYYYs.Where(x => x.Name == "hogehoge").ToArray();補足(
IQueryableとIEnumerableの境界): この 2 つの節の違いは
「どこで SQL に変換されるか」であり、性能上もっとも重要な論点である。
IQueryable(LINQ to Entities): 式ツリーが SQL に翻訳され、
DB 側で絞り込まれるIEnumerable(LINQ to Objects): 先に全件をメモリに読み込み、
アプリ側で絞り込む
ToArray()/ToList()/AsEnumerable()を挟んだ時点で
境界を越えるため、以下はテーブル全件を読み込んでから絞り込む。// NG: 全件フェッチしてからメモリ上で Where var bad = context.YYYYYs.ToArray().Where(x => x.Name == "hogehoge"); // OK: WHERE 句として SQL に翻訳される var good = await context.YYYYYs .Where(x => x.Name == "hogehoge") .ToArrayAsync();
全体的に実行される SQL がブラックボックスで性能を意識し難い
(Entity Framework の懸念)。
補足(発行 SQL を見る): ブラックボックス性は、
ログを出せば大幅に緩和できる。
- EF Core:
optionsBuilder.LogTo(Console.WriteLine)および
EnableSensitiveDataLogging()(開発環境のみ)- EF6:
context.Database.Log = Console.Write;- DB 側: SQLプロファイラ(SQLトレース)や拡張イベント
(SQL Server のログ)で実際の実行を確認する特に N+1 問題は、ログを見れば一目で分かる。
関連エンティティはIncludeでまとめて取得する。
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();
}移行メモ(正誤): コメントの「Unchanged 状態 → Added 状態へ」は、
新規生成した Entity は追跡されていないため
正しくは「Detached 状態 → Added 状態へ」である。
using (var context = new XXXXXContext())
{
var yyyyy = context.YYYYYs.Single(x => x.Name == "hogehoge");
yyyyy.Name = "Aiueo";
context.SaveChanges();
}- Select ---> Delete
using (var context = new XXXXXContext())
{
var yyyyy = context.YYYYYs.Single(x => x.Name == "hogehoge");
context.YYYYYs.Remove(yyyyy);
context.SaveChanges();
}- 直接 Delete
using (var context = new XXXXXContext())
{
var toRemoveYyyyy = new YYYYY { Id = 1 };
context.YYYYYs.Attach(toRemoveYyyyy);
context.YYYYYs.Remove(toRemoveYyyyy);
context.SaveChanges();
}補足(最新化:一括更新・削除): 上記はいずれも
1 行ごとにUPDATE/DELETEを発行するため、
大量件数のバッチでは破綻する。
EF Core 7 以降は、SQL 1 発で処理する API が追加されている。// 1 回の DELETE 文になる(SaveChanges は不要) await context.YYYYYs .Where(x => x.CreatedAt < threshold) .ExecuteDeleteAsync(); // 1 回の UPDATE 文になる await context.YYYYYs .Where(x => x.Name == "hogehoge") .ExecuteUpdateAsync(s => s.SetProperty(x => x.Name, "Aiueo"));さらに大量の挿入は
SqlBulkCopyを使うほうが桁違いに速い。
- Entity Framework のお役立ち記事まとめ ある SE のつぶやき
http://fnya.cocolog-nifty.com/blog/2014/01/entity-frame-13.html
-
LINQとの関連もチェックして下さい。
-
書籍転載:ASP.NET MVC 5 実践プログラミング - LINQ とは?[C#] - Build Insider
http://www.buildinsider.net/web/bookaspmvc5/050301 -
連載:ADO.NET Entity Framework 入門 - @IT
第3回 Entity Framework におけるクエリと更新
http://www.atmarkit.co.jp/fdotnet/ef4basic/ef4basic03/ef4basic03_02.html -
LINQ to Entities | Microsoft Learn
https://learn.microsoft.com/ja-jp/dotnet/framework/data/adonet/ef/language-reference/linq-to-entitiesLINQ to Entities, QueryBuilder, Entity SQL
-
.NET の新データアクセス・テクノロジ「ADO.NET Entity Framework」 - @IT
http://www.atmarkit.co.jp/fdotnet/special/vs2008sp1ef/vs2008sp1ef_01.html -
連載:ADO.NET Entity Framework 入門 - @IT
http://www.atmarkit.co.jp/fdotnet/ef4basic/index/index.html- 第1回 最新 DB アクセス・フレームワークの基本的な考え方
- 第2回 EDM における多対多関係と Entity Framework でのデータの取得/保存
- 第3回 Entity Framework におけるクエリと更新
- 第4回 データベースからの Entity Data Model 生成
- 第5回 POCO によるエンティティ・クラス
- 第6回 EF4 による N 層アーキテクチャと自己追跡エンティティ【前編】
- 第7回 EF4 による N 層アーキテクチャと自己追跡エンティティ【後編】
-
エンティティ フレームワークの概要
https://learn.microsoft.com/ja-jp/dotnet/framework/data/adonet/ef/overview -
パフォーマンスに関する考慮事項 (Entity Framework)
https://learn.microsoft.com/ja-jp/dotnet/framework/data/adonet/ef/performance-considerations
- Entity Framework
https://learn.microsoft.com/ja-jp/ef/
- データ ポイント
- Dapper、Entity Framework、およびハイブリッド アプリ
- EF Core の変更追跡の動作: 変更なし、変更済み、および追加
- .NET Framework と .NET Core の両方での EF Core の実行
- EF Core 1.1: お気に入りをいくつか
- EF Core と InMemory プロバイダーを使ったテスト作成のヒント
- DDD に最適な EF Core 2.0
- DDD に最適な EF Core 2.0 (第 2 部)
補足(
InMemoryプロバイダについて): 上記記事にある
InMemoryプロバイダは、現在テスト用途に推奨されていない。
リレーショナル DB の制約(一意制約、外部キー、トランザクション)を
再現しないため、テストが通っても本番で落ちる。
現在は SQLite の in-memory モードか、
Testcontainers で実 DBMS を立てる方式が推奨されている。
- 雲のごとく - Site Home - MSDN Blogs
- .NET Framework 4.5 におけるデータ アクセスの概要 その1
- .NET Framework 4.5 におけるデータ アクセスの概要 その3 ~ ADO.NET Entity Framework
- Entity Framework Core 1.0 正式リリース – 雲のごとく
Tags: 移行, .NET開発, データアクセス, ADO.NET, Entity Framework
このWikiは「Open棟梁Project」,「OSSコンソーシアム 開発基盤部会」によって運営されています。