75
ADO.NET Entity Framework を使いこなそう 福井 厚 ( Twitter: @afukui ) VSUG運営委員 Microsoft Certified Architect Microsoft Regional Director Microsoft MVP for Visual C# VSUG DAY 2010 Summer

VSUG Day 2010 Summer - Using ADO.NET Entity Framework

Embed Size (px)

DESCRIPTION

This presentataion slide describes Microsoft.NET Framework 4 ADO.NET Entity Framework and was used for VSUG Day 2010 Summer in Japan. VSUG (Visual Studio Users Group)

Citation preview

Page 1: VSUG Day 2010 Summer - Using ADO.NET Entity Framework

ADO.NET Entity Framework

を使いこなそう

福井 厚 ( Twitter: @afukui ) VSUG運営委員

Microsoft Certified Architect

Microsoft Regional Director

Microsoft MVP for Visual C#

VSUG DAY 2010 Summer

Page 2: VSUG Day 2010 Summer - Using ADO.NET Entity Framework

VSUG DAY 2010.05.09

自己紹介

福井 厚 (ふくい あつし) アバナード株式会社

Group Manager / CTO Architect

Visual Studio User Group 運営委員

Microsoft Certified Architect (MCA)

Microsoft Regional Director

Microsoft MVP for Visual Developer – C#

Blog: http://www.users.gr.jp/blogs/fukui/

Twitter: @afukui

Page 3: VSUG Day 2010 Summer - Using ADO.NET Entity Framework

VSUG DAY 2010.05.09

突然ですがアンケートを実施

Page 4: VSUG Day 2010 Summer - Using ADO.NET Entity Framework

VSUG DAY 2010.05.09

Agenda

ADO.NET Entity Frameworkとは

EDM(Entity Domain Model)とは

ObjectServicesとクエリ

オブジェクトの追加、更新、削除

同時実行制御

エンティティ状態と変更の追跡

エンティティの継承と抽象化

N層アプリと自己追跡エンティティ

まとめ

Page 5: VSUG Day 2010 Summer - Using ADO.NET Entity Framework

VSUG DAY 2010.05.09

一般的な設計アプローチ

ドメイン モデル、設計モデル、物理モデルの3つに分割

ドメイン モデル

対象となるシステムに存在するエンティティとリレーションシップを定義

設計モデル

外部キー制約を用いながら、エンティティとリレーションシップをテーブルとして正規化(RDBの場合)

物理モデル

パーティション分割やインデックス化などのストレージ情報を指定することで、特定のデータ エンジンの機能に対応

Page 6: VSUG Day 2010 Summer - Using ADO.NET Entity Framework

VSUG DAY 2010.05.09

開発アプローチ

ドメイン モデル駆動

概念モデルをストレートにマッピング

複雑なビジネス ロジック

データベース駆動

データ中心アプローチ

既存のDBテーブルの活用

ユーザー インターフェース駆動

モックアップから開発

Page 7: VSUG Day 2010 Summer - Using ADO.NET Entity Framework

VSUG DAY 2010.05.09

Page 8: VSUG Day 2010 Summer - Using ADO.NET Entity Framework

VSUG DAY 2010.05.09

Entity Frameworkとは

データ指向のソフトウェア アプリケーション開発をサポートする ADO.NET のテクノロジ セット

データが格納されている、基になるデータベース テーブルや列を意識することなく、顧客や顧客の住所など、ドメイン固有のオブジェクトおよびプロパティの形式でデータを扱うことが可能

EDM(後述)の実装を提供

Page 9: VSUG Day 2010 Summer - Using ADO.NET Entity Framework

VSUG DAY 2010.05.09

Entity Framework Architecture

Entity Domain Model Object Services ObjectContext

ObjectQuery<T>

Data Class

EntityClient EntityConnection

EntityCommand

EntityDataReader

CSDL

MSL

SSDL

Page 10: VSUG Day 2010 Summer - Using ADO.NET Entity Framework

VSUG DAY 2010.05.09

Page 11: VSUG Day 2010 Summer - Using ADO.NET Entity Framework

VSUG DAY 2010.05.09

EDM(Entity Domain Model)とは

格納される形式に関係なく、データ構造を記述する一連の概念

ストレージ スキーマに依存しないエンティティとリレーションシップでデータ構造を記述

エンティティおよびリレーションシップによりアプリケーションで使用されるデータ構造 (格納形式ではなく) が記述されるため、アプリケーションの進化に伴ってこれらを進化させることが可能

Page 12: VSUG Day 2010 Summer - Using ADO.NET Entity Framework

VSUG DAY 2010.05.09

概念モデル、論理モデル、マッピング

概念スキーマ 定義言語(CSDL)

EDMの概念を実装するDSL(Domain Specific

Language)の1種

ストア スキーマ 定義言語(SSDL)

マッピング 仕様言語ファイル (MSL)

Page 13: VSUG Day 2010 Summer - Using ADO.NET Entity Framework

VSUG DAY 2010.05.09

Entity Data Model の概念

エンティティ型

Entity Data Model でデータ構造を記述するために不可欠な構成要素

継承をサポート

アソシエーション型

Entity Data Model でリレーションシップを記述するために不可欠な構成要素

アソシエーションに含まれるエンティティ型を指定する 2 つのアソシエーション End がある

アソシエーションのその End に存在できるエンティティ数を示すアソシエーション End の多重度も指定する必要がある

プロパティ

エンティティ型には、その構造と特性を定義するプロパティが含まれる

プロパティには、プリミティブ データ (文字列、整数、ブール値など) または構造化データ (複合型) を含めることができる

Page 14: VSUG Day 2010 Summer - Using ADO.NET Entity Framework

VSUG DAY 2010.05.09

Entity Data Model でサポートされるプリミティブ データ型

プリミティブデータ型

説明 私用できるファセット

Binary バイナリ データを格納 MaxLength、FixedLength、Nullable、Default

Boolean true または false Nullable、Default

Byte 符号なし 8 ビット整数値

Precision、Nullable、Default

DateTime 日時 Precision、Nullable、Default

DateTimeOffset GMT からのオフセット

(分単位) としての日時

Precision、Nullable、Default

Decimal 有効桁数と小数点以下桁数が固定長の数値

Precision、Nullable、Default

Double 15 桁の有効桁数を持つ浮動小数点数

Precision、Nullable、Default

Float 7 桁の有効桁数を持つ浮動小数点数

Precision、Nullable、Default

Page 15: VSUG Day 2010 Summer - Using ADO.NET Entity Framework

VSUG DAY 2010.05.09

Entity Data Model でサポートされるプリミティブ データ型

プリミティブデータ型

説明 私用できるファセット

Guid 16 バイトの一意識別子 Precision、Nullable、Default

Int16 符号付き 16 ビット整数値

Precision、Nullable、Default

Int32 符号付き 32 ビット整数値

Precision、Nullable、Default

Int64 符号付き 64 ビット整数値

Precision、Nullable、Default

SByte 符号付き 8 ビット整数値

Precision、Nullable、Default

String 文字データ Unicode、FixedLength、MaxLength、Collation、Precision、Nullable、Default

Time 時刻を格納 Precision、Nullable、Default

Page 16: VSUG Day 2010 Summer - Using ADO.NET Entity Framework

VSUG DAY 2010.05.09

アソシエーション End

アソシエーションに2つのアソシエーション

End

アソシエーション Endの定義に含まれる情報

アソシエーションに含まれるエンティティ型

多重度(1, 0..1, *)

Endの名前

CASCADE ON DELETEなどの操作

Page 17: VSUG Day 2010 Summer - Using ADO.NET Entity Framework

VSUG DAY 2010.05.09

ADO.NET Entity Data Modelの作成

Page 18: VSUG Day 2010 Summer - Using ADO.NET Entity Framework

VSUG DAY 2010.05.09

Page 19: VSUG Day 2010 Summer - Using ADO.NET Entity Framework

VSUG DAY 2010.05.09

Object Servicesの概要

Entity Framework ツールは、概念スキーマ定義言語

(CSDL) ファイルを使用して、オブジェクト レイヤー

コードを生成

生成されるコードに含まれるデータクラス

型指定された ObjectContext クラス

エンティティ型を表し、EntityObject から継承したクラス

複合型を表し、ComplexObject から継承したクラス

オブジェクト コンテキスト

以下のものをカプセル化

データベースへの接続

モデルを記述するメタデータ

作成、更新、および削除の操作時にオブジェクトを追跡する

ObjectStateManager オブジェクト

Page 20: VSUG Day 2010 Summer - Using ADO.NET Entity Framework

VSUG DAY 2010.05.09

オブジェクト クエリ

エンティティ セットを返す

ObjectQuery (.NET Framework 3.5 SP1)

ObjectSet (.NET Framework 4) ObjectQueryクラスを拡張、型指定されたエンティティ セットのコンテキストでオブジェクトの追加や削除の機能を追加

using (ChinookEntities context = new ChinookEntities())

{

ObjectSet<Album> albums = context.Albums;

var query = from album in albums

where album.Artist.Name == "Deep Purple"

select new { Title = album.Title, Name = album.Artist.Name };

Console.WriteLine("Album title: ");

foreach (var q in query)

{

Console.WriteLine(q.Name + ": " + q.Title);

}

Page 21: VSUG Day 2010 Summer - Using ADO.NET Entity Framework

VSUG DAY 2010.05.09

クエリを返す方法

LINQ to Entities 概念モデルで定義されているエンティティ型に対してクエリを実行するための統合言語クエリ (LINQ) をサポート

Entity SQL

SQL.ストレージに依存しない SQL 言語。概念モデルのエンティティを直接操作し、Entity Data Model の概念をサポート

クエリービルダーメソッド

LINQ スタイルのクエリ メソッドを使用して Entity

SQL クエリを構成

Page 22: VSUG Day 2010 Summer - Using ADO.NET Entity Framework

VSUG DAY 2010.05.09

Entity SQL

Entity Framework 内の概念モデルに対するクエリの実行に使用できる SQL に似た言語

概念モデルは、データをエンティティおよびリレーションシップとして表す

Entity SQL を使用すると、SQL を使用したことのあるユーザーが慣れている形式でそれらのエンティティおよびリレーションシップに対してクエリを実行できる

SELECT VALUE p.Name FROM AdventureWorksEntities.Product as p

Page 23: VSUG Day 2010 Summer - Using ADO.NET Entity Framework

VSUG DAY 2010.05.09

クエリービルダーメソッド

ObjectQuery には、Entity SQL と等価のクエリ コマンドを順番に構築するために使用できる一連のクエリ ビルダー メソッドも実装されている

Distinct(), Except(), GroupBy(), Intersect(),

OfType(), OrderBy(), Select(), SelectValue(), Skip(), Top(), Union(), UnionAll(), Where() など

Page 24: VSUG Day 2010 Summer - Using ADO.NET Entity Framework

VSUG DAY 2010.05.09

クエリの実行 LINQ to Entities

Page 25: VSUG Day 2010 Summer - Using ADO.NET Entity Framework

VSUG DAY 2010.05.09

LINQ to Entities

メソッドベースの構文例(射影)

using (AdventureWorksEntities AWEntities = new AdventureWorksEntities())

{

var query = AWEntities.Products

.Select(product => new

{

ProductId = product.ProductID,

ProductName = product.Name

});

Console.WriteLine("Product Info:");

foreach (var productInfo in query)

{

Console.WriteLine("Product Id: {0} Product name: {1} ",

productInfo.ProductId, productInfo.ProductName);

}

}

Page 26: VSUG Day 2010 Summer - Using ADO.NET Entity Framework

VSUG DAY 2010.05.09

LINQ to Entities

クエリ式の構文例(射影)

using (AdventureWorksEntities AWEntities = new AdventureWorksEntities())

{

ObjectSet<Product> products = AWEntities.Products;

IQueryable<Product> productsQuery = from product in products

select product;

Console.WriteLine("Product Names:");

foreach (var prod in productsQuery)

{

Console.WriteLine(prod.Name);

}

}

Page 27: VSUG Day 2010 Summer - Using ADO.NET Entity Framework

VSUG DAY 2010.05.09

LINQ to Entities

クエリ式の構文例(フィルター処理)

ObjectSet<SalesOrderHeader> orders = AWEntities.SalesOrderHeaders;

var onlineOrders =

from order in orders

where order.OnlineOrderFlag == true

select new

{

SalesOrderID = order.SalesOrderID,

OrderDate = order.OrderDate,

SalesOrderNumber = order.SalesOrderNumber

};

Page 28: VSUG Day 2010 Summer - Using ADO.NET Entity Framework

VSUG DAY 2010.05.09

LINQ to Entities

クエリ式の構文例(集計演算子処理)

ObjectSet<Product> products = AWEntities.Products;

var query = from product in products

group product by product.Style into g

select new

{

Style = g.Key,

AverageListPrice =

g.Average(product => product.ListPrice)

};

foreach (var product in query)

{

Console.WriteLine("Product style: {0} Average list price: {1}",

product.Style, product.AverageListPrice);

}

Page 29: VSUG Day 2010 Summer - Using ADO.NET Entity Framework

VSUG DAY 2010.05.09

LINQ to Entities

クエリ式の構文例(パーティション分割)

var query = (from album in albums

where album.Artist.Name == "Deep Purple"

orderby album.Title

select new

{

Title = album.Title,

Name = album.Artist.Name

}).Take(3);

Page 30: VSUG Day 2010 Summer - Using ADO.NET Entity Framework

VSUG DAY 2010.05.09

LINQ to Entities

クエリ式の構文例(結合演算子)

GroupJoin() 左外部結合に相当

var query =

from contact in contacts

join order in orders

on contact.ContactID

equals order.Contact.ContactID into contactGroup

select new

{

ContactID = contact.ContactID,

OrderCount = contactGroup.Count(),

Orders = contactGroup.Select(order => order)

};

Page 31: VSUG Day 2010 Summer - Using ADO.NET Entity Framework

VSUG DAY 2010.05.09

LINQ to Entities

クエリ式の構文例(グループ化)

var query = (

from contact in contacts

group contact by contact.LastName.Substring(0, 1) into contactGroup

select new { FirstLetter = contactGroup.Key,

ContactGroup = contactGroup }).

OrderBy(letter => letter.FirstLetter);

foreach (var contact in query)

{

Console.WriteLine("Last names that start with the letter '{0}':",

contact.FirstLetter);

foreach (var name in contact.ContactGroup)

{

Console.WriteLine(name.LastName);

}

}

Page 32: VSUG Day 2010 Summer - Using ADO.NET Entity Framework

VSUG DAY 2010.05.09

関連オブジェクトの読み込み

読み込みパターン 説明

クエリで指定する ナビゲーション プロパティを使用

明示的読み込み Loadメソッドを使用

遅延読み込み LazyLoadingEnabledプロパティをtrueにセット

一括読み込み ObjectQuery で Include(String) メソッドを使用

Page 33: VSUG Day 2010 Summer - Using ADO.NET Entity Framework

VSUG DAY 2010.05.09

関連するオブジェクトを明示的に読み込む

Contact customer = context.Contacts

.Where("it.ContactID = @customerId",

new ObjectParameter("customerId", customerId)).First();

if (!customer.SalesOrderHeaders.IsLoaded)

{

customer.SalesOrderHeaders.Load();

}

foreach (SalesOrderHeader order in customer.SalesOrderHeaders)

{

if (!order.SalesOrderDetails.IsLoaded)

{

order.SalesOrderDetails.Load();

}

Page 34: VSUG Day 2010 Summer - Using ADO.NET Entity Framework

VSUG DAY 2010.05.09

遅延読み込み

Entity Framework ツールを使用して新しいモデルおよび対応する生成済みクラスを作成する場合、LazyLoadingEnabled の既定値は true

遅延読み込みは、単一オブジェクト (EntityReference など) とオブジェクトのコレクション (EntityCollection など) の両方を返すナビゲーション プロパティでサポート

遅延読み込みが有効であっても、関連オブジェクトが既に読み込まれているなら、関連オブジェクトが再度読み込まれることはない

遅延読み込みは、Detached() 状態にあるオブジェクトでサポートされる。この場合、関連オブジェクトも

Detached() 状態で返される

context.ContextOptions.LazyLoadingEnabled = true;

Page 35: VSUG Day 2010 Summer - Using ADO.NET Entity Framework

VSUG DAY 2010.05.09

一括読み込み(クエリ パスの定義)

var contacts = (from contact in context.Contacts

.Include("SalesOrderHeaders.SalesOrderDetails")

select contact).FirstOrDefault();

try

{

foreach (SalesOrderHeader order in contacts.SalesOrderHeaders)

{

Console.WriteLine(String.Format("PO Number: {0}",

order.PurchaseOrderNumber));

Console.WriteLine(String.Format("Order Date: {0}",

order.OrderDate.ToString()));

Console.WriteLine("Order items:");

foreach (SalesOrderDetail item in order.SalesOrderDetails)

{

Console.WriteLine(String.Format("Product: {0} "

+ "Quantity: {1}", item.ProductID.ToString(),

item.OrderQty.ToString()));

}

}

Page 36: VSUG Day 2010 Summer - Using ADO.NET Entity Framework

VSUG DAY 2010.05.09

Page 37: VSUG Day 2010 Summer - Using ADO.NET Entity Framework

VSUG DAY 2010.05.09

オブジェクトの作成と追加

using (ChinookEntities context = new ChinookEntities())

{

ObjectSet<Artist> artists = context.Artists;

//ArtistIdはIdentityとして宣言されているので、初期値(0)は無視される

Artist artist = Artist.CreateArtist(0);

artist.Name = "Atsushi Fukui";

artists.AddObject(artist);

context.SaveChanges();

Console.WriteLine("Added Artist id {0} name {1}", artist.ArtistId, artist.Name);

Page 38: VSUG Day 2010 Summer - Using ADO.NET Entity Framework

VSUG DAY 2010.05.09

オブジェクトの削除

using (ChinookEntities context = new ChinookEntities())

{

ObjectSet<Artist> artists = context.Artists;

Artist artist = artists.Where("it.Name=@name",

new ObjectParameter("name", "Atsushi Fukui")).First();

if (artist != null)

{

artists.DeleteObject(artist);

context.SaveChanges();

}

}

Page 39: VSUG Day 2010 Summer - Using ADO.NET Entity Framework

VSUG DAY 2010.05.09

オブジェクトの更新

object entity = null;

IEnumerable<KeyValuePair<string, object>> keyValues =

new KeyValuePair<string, object>[]{

new KeyValuePair<string, object>("ArtistId", 279)

};

EntityKey key = new EntityKey("ChinookEntities.Artists", keyValues);

if (context.TryGetObjectByKey(key, out entity))

{

Artist artist = (Artist)entity;

artist.Name = "Hideharu Moriya";

context.SaveChanges();

}

Artist a = context.Artists.Where(o => o.ArtistId == 279).First();

if (a != null)

{

Console.WriteLine(“artist id {0}, name {1}”, a.ArtistId, a.Name);

}

Page 40: VSUG Day 2010 Summer - Using ADO.NET Entity Framework

VSUG DAY 2010.05.09

ID管理、状態管理、変更の追跡

ObjectStateEntry アタッチされている各オブジェクトに対して作成される

EntityKey と EntityState、関連するオブジェクトに関する情報、およびオブジェクトのプロパティの元の値と現在の値を格納

エンティティがデタッチされると、対応する

ObjectStateEntry オブジェクトがオブジェクト コンテキストから削除される

ObjectStateManager によって管理される

各オブジェクト コンテキストについて、ObjectStateManager のインスタンスが 1 つ存在

Page 41: VSUG Day 2010 Summer - Using ADO.NET Entity Framework

VSUG DAY 2010.05.09

エンティティ状態

マージ

オプション

説明

Added 新しいオブジェクトがオブジェクト コンテキストに追加されている。SaveChanges() メソッドは呼び出されていない。変更が保存されると、オブジェクトの状態は Unchangedに変更される。

Deleted オブジェクトがオブジェクト コンテキストから削除されている。変更が保存されると、オブジェクトの状態は Detachedに変更される。

Detached オブジェクトが存在するが追跡されていない。エンティティは、作成された直後とオブジェクト コンテキストに追加される直前にこの状態になる。また、Detach(Object) メソッドを呼び出してコンテキストから削除された後、または NoTracking MergeOption を使用して読み込まれる場合にもこの状態になる。

Modified オブジェクトのスカラー プロパティのいずれかが変更されている。SaveChangesメソッドは呼び出されていない。変更追跡プロキシを持たない POCO エンティティでは、DetectChangesメソッドが呼び出されたときに、変更されているプロパティの状態が Modified に変わる。変更が保存されると、オブジェクトの状態は Unchangedに変わる。

Unchanged オブジェクトは、コンテキストに読み込まれた後、または最後に

SaveChanges メソッドが呼び出されてから変更されていない。

Page 42: VSUG Day 2010 Summer - Using ADO.NET Entity Framework

VSUG DAY 2010.05.09

変更の追跡

Entity Framework により生成されたエンティティおよび変更追跡プロキシ オブジェクトを持つ POCO エンティティに対しては、ObjectStateEntry はオブジェクト プロパティの現在の値および変更されたプロパティの元の値を格納する

Added 状態または Detached 状態にあるオブジェクトは、元の値を保持していない

オブジェクト コンテキストは、プロパティが変更されると通知を受け取り、ObjectStateEntry 内のオブジェクトの状態とプロパティの値を更新する

ObjectStateEntry は、変更追跡プロキシの無いPOCOエンティティ、および複合型オブジェクトでは異なる方法で管理する。これらの型のオブジェクトに対し、ObjectStateEntryは、オブジェクトが最初にコンテキストに入った時にオブジェクト プロパティの値のスナップショットを取得し、元の値のセットと現在の値のセットを格納する。

Page 43: VSUG Day 2010 Summer - Using ADO.NET Entity Framework

VSUG DAY 2010.05.09

ID解決とマージ

特定のエンティティ キーを持つオブジェクトの

1 つのみのインスタンスをキャッシュ内に保持する

同じ ID を持つエンティティが既に追跡されている場合、データ ソースからのデータと状態マネージャーに既に存在するデータは、クエリの

MergeOption に従ってマージされる

var orders = Customer.Orders.Execute(MergeOption.PreserveChanges);

Page 44: VSUG Day 2010 Summer - Using ADO.NET Entity Framework

VSUG DAY 2010.05.09

マージ オプション

マージ オプション 説明

AppendOnly オブジェクト コンテキストに存在しないオブジェクトは、コンテキストにアタッチされる。オブジェクト コンテキストに存在するオブジェクトのプロパティは、データ ソースの値によって上書きされない。AppendOnly()

は既定のマージ オプション

OverwriteChanges オブジェクト コンテキストに存在しないオブジェクトは、コンテキストにアタッチされる。オブジェクト コンテキストに存在するオブジェクトのプロパティは、データ ソースの値によって上書きされる。

PreserveChanges .NET Framework バージョン 3.5 SP1 では、オブジェクト コンテキスト内のオブジェクトのプロパティ値がサーバー上の値と異なる場合、オブジェクト コンテキスト内のプロパティ値は、オブジェクトが Unchanged状態にない限り、保持される。Unchanged状態の場合は、プロパティがデータ

ソースの値で上書きされる。

.NET Framework バージョン 4 では、オブジェクト コンテキスト内のオブジェクトの値はすべて、オブジェクトの状態にかかわらず保持される。

NoTracking オブジェクトは、Detached状態で保持され、ObjectStateManager では追跡されない。ただし、Entity Framework により生成されたエンティティおよびプロキシを持つ POCO エンティティは、関連するオブジェクトの読み込みを容易にするために、オブジェクト コンテキストへの参照を保持する。

Page 45: VSUG Day 2010 Summer - Using ADO.NET Entity Framework

VSUG DAY 2010.05.09

同時実行制御チェック

ConcurrencyMode=“Fixed” を使用するとEntity Framework は、変更をデータベースに保存する前に、データベース内の変更をチェックする

SQL Serverの場合、各テーブルにタイムスタンプ列を追加して指定すると良い

他のデータベースの場合はトリガでタイムスタンプを更新するなど

Page 46: VSUG Day 2010 Summer - Using ADO.NET Entity Framework

VSUG DAY 2010.05.09

同時実行制御チェック

Page 47: VSUG Day 2010 Summer - Using ADO.NET Entity Framework

VSUG DAY 2010.05.09

Page 48: VSUG Day 2010 Summer - Using ADO.NET Entity Framework

VSUG DAY 2010.05.09

Entity Data Model: 継承

概念モデルでは派生型は基本型のすべてのプロパティとナビゲーション プロパティを継承

ルート型はエンティティ キーを定義する必要がある

単一継承のみ可能

CSDLによる定義例

<EntityType Name="FictionBook" BaseType="BooksModel.Book" >

<Property Type="String" Name="Genre" Nullable="false" />

</EntityType>

Page 49: VSUG Day 2010 Summer - Using ADO.NET Entity Framework

VSUG DAY 2010.05.09

概念モデルの継承の実装方式

Table-Per-Type継承

概念スキーマで派生型のBaseType属性に基本エンティティ型を指定

基本エンティティを抽象型として定義

派生型のIDを削除

マッピングの詳細ウィンドウでIDを基本エンティティのIDにマップ

Table-Per-Hierarchy 継承

概念スキーマで派生型のBaseType属性に基本エンティティ型を指定

マッピングの詳細ウィンドウで「テーブルまたはビューの追加」からテーブルを選択

条件の追加でプロパティにIs NullまたはIs Not Nullを設定

Page 50: VSUG Day 2010 Summer - Using ADO.NET Entity Framework

VSUG DAY 2010.05.09

自動生成されるSQLの一部

-- Creating table 'Parties'

CREATE TABLE [dbo].[Parties] (

[Id] int IDENTITY(1,1) NOT NULL,

[Name] nvarchar(max) NOT NULL

);

GO

-- Creating table 'Parties_Organization'

CREATE TABLE [dbo].[Parties_Organization] (

[Location] nvarchar(max) NOT NULL,

[Id] int NOT NULL

);

GO

-- Creating table 'Parties_Person'

CREATE TABLE [dbo].[Parties_Person] (

[Age] int NOT NULL,

[Id] int NOT NULL

);

GO

Page 51: VSUG Day 2010 Summer - Using ADO.NET Entity Framework

VSUG DAY 2010.05.09

エンティティの継承

Page 52: VSUG Day 2010 Summer - Using ADO.NET Entity Framework

VSUG DAY 2010.05.09

Page 53: VSUG Day 2010 Summer - Using ADO.NET Entity Framework

VSUG DAY 2010.05.09

N層アプリケーションとは

クライアント層、中間サービス層、データベース層に分かれる

ASP.NETアプリケーション

WCFサービス、Webサービスを利用するアプリケーション

Silverlightアプリケーション

オブジェクトをシリアル化して他の層に転送し逆シリアル化して利用

更新された情報を何らかの方法で保持する必要がある

Page 54: VSUG Day 2010 Summer - Using ADO.NET Entity Framework

VSUG DAY 2010.05.09

オブジェクトのシリアル化

オブジェクトをシリアル化すると、EntityKey オブジェクトもシリアル化される

バイナリ シリアル化と WCF データ コントラクト シリアル化を使用する場合に、シリアル化するオブジェクトのオブジェクト グラフに関連オブジェクトがあると、これらのオブジェクトもシリアル化される

XML シリアル化では、関連オブジェクトはシリアル化されない

オブジェクトのプロパティとリレーションシップ情報だけがシリアル化される

オブジェクト コンテキストで維持されているオブジェクトの状態情報はシリアル化されない

.NET Framework バージョン 4 から、自己追跡エンティティで独自の変更追跡ロジックを利用できるようになった(後述)

オブジェクトが逆シリアル化された後、オブジェクトは Detached()

状態になる

Page 55: VSUG Day 2010 Summer - Using ADO.NET Entity Framework

VSUG DAY 2010.05.09

オブジェクトのアタッチ、デタッチ

Entity Framework では、オブジェクト コンテキスト内でクエリを実行すると、返されたオブジェクトがそのオブジェクト コンテキストに自動的にアタッチされる

以前にデタッチされているオブジェクト、NoTracking() クエリによって返されたオブジェクト、またはオブジェクト コンテキストの外部で取得したオブジェクトなどもアタッチできる

ASP.NET アプリケーションのビュー ステートに保存されていたオブジェクトや、リモート メソッド呼び出しまたは Web サービスによって返されたオブジェクトもアタッチできる

Page 56: VSUG Day 2010 Summer - Using ADO.NET Entity Framework

VSUG DAY 2010.05.09

変更の適用(デタッチ オブジェクト)

単純にアタッチされた場合、そのオブジェクトが既にオブジェクト コンテキスト内にあると、更新が失われるか、操作が失敗する(Unchanged状態でアタッチされるため)

オリジナルのオブジェクトと変更後のオブジェクトをクライアントから返してもらうことでオブジェクト コンテキストにアタッチしたオブジェクトに変更を適用する

Page 57: VSUG Day 2010 Summer - Using ADO.NET Entity Framework

VSUG DAY 2010.05.09

オブジェクトをアタッチするメソッド

メンバー 説明

ObjectSetAddObject() または

ObjectContextAddObject(S

tring, Object)

オブジェクトとその関連オブジェクトを ObjectContext

に追加し、エンティティ オブジェクトを Added 状態に設定します。この状態では、エンティティ オブジェクトの一意のキー値を持つ必要はない。一時的なキー値がキーのプロパティに割り当てられ、オブジェクトの保存後にデータ ソースが生成した値で更新される。オブジェクトを追加後、エンティティ オブジェクトの状態が適切に変更される。

ObjectSetAttach() または

ObjectContextAttach(IEntit

yWithKey) と

AttachTo(String, Object)

オブジェクトを ObjectContext に追加し、オブジェクトを Unchanged 状態に設定する。Unchanged 状態では、Entity Framework はエンティティ キーの値を最終版として処理する。特定の型の複数のエンティティに同じキーの値がある場合は、Entity Framework は例外をスローする。例外を回避するには、AddObject メソッドを使用してデタッチされたオブジェクトをアタッチし、適切な状態に変更する。

Page 58: VSUG Day 2010 Summer - Using ADO.NET Entity Framework

VSUG DAY 2010.05.09

アタッチして変更を適用する例

private static void ApplyItemUpdates(

SalesOrderDetail originalItem, SalesOrderDetail updatedItem)

{

using (AdventureWorksEntities advWorksContext = new AdventureWorksEntities())

{

try

{ //オリジナルのItemをオブジェクト コンテキストにアタッチ

advWorksContext.Attach(originalItem);

//変更を適用するためにApplyCurrentValuesメソッドを使用

advWorksContext.ApplyCurrentValues(“SalesOrderDetails”, updatedItem);

advWorksContext.SaveChanges();

}

catch (InvalidOperationException ex)

{

Console.WriteLine(ex.ToString());

}

}

}

Page 59: VSUG Day 2010 Summer - Using ADO.NET Entity Framework

VSUG DAY 2010.05.09

自己追跡エンティティ

Page 60: VSUG Day 2010 Summer - Using ADO.NET Entity Framework

VSUG DAY 2010.05.09

自己追跡エンティティ

//クライアント側コード

static void UpdateDepartmentAndCourses(int departmentID, int courseID)

{

using (var service = new Service1Client())

{

List<Department> departments = service.GetDepartments();

Department department = departments.Single(

d => d.DepartmentID == departmentID);

department.Budget = department.Budget - 1000.00m;

Course existingCourse = department.Courses.Single(

c => c.CourseID == courseID);

existingCourse.Credits = 3;

service.UpdateDepartment(department);

}

}

Page 61: VSUG Day 2010 Summer - Using ADO.NET Entity Framework

VSUG DAY 2010.05.09

自己追跡エンティティ

//サービス側コード

public void UpdateDepartment(Department updated)

{

using (SchoolEntities context = new SchoolEntities())

{

try

{

context.Departments.ApplyChanges(updated);

context.SaveChanges();

}

catch (UpdateException)

{

throw;

}

}

}

Page 62: VSUG Day 2010 Summer - Using ADO.NET Entity Framework

VSUG DAY 2010.05.09

まとめ

ADO.NET Entity FrameworkはEDMの実装を提供

概念スキーマ定義とストア スキーマ定義をマッピングすることでストアに非依存なモデルを利用可能

エンティティとアソシエーションの概念

同時実行制御チェックを有効にする

オブジェクト状態を理解する

N層アプリケーションと自己追跡エンティティ

WCF サービス アプリケーションとの連携

ObjectContextをサービス層でキャッシュするのはアンチパタン

継承エンティティによるテーブル マッピング

その他

IObjectSetの利用によってテスト容易性が向上している

Page 63: VSUG Day 2010 Summer - Using ADO.NET Entity Framework

VSUG DAY 2010.05.09

参考資料

Entity Framework を使用した n 層アプリケーションで回避すべきアンチパターン http://msdn.microsoft.com/ja-jp/magazine/dd882522.aspx

n 層アプリケーションのパターン http://msdn.microsoft.com/ja-jp/magazine/ee321569.aspx

チュートリアル: ストアド プロシージャへのエンティティのマッピング http://msdn.microsoft.com/ja-jp/library/cc716679(v=VS.100).aspx

Walkthrough: Serialize Self-Tracking Entities (Entity Framework) (英語) http://msdn.microsoft.com/en-us/library/ee789839(v=VS.100).aspx

Entity Framework FAQ(英語) http://blogs.msdn.com/dsimmons/pages/entity-framework-faq.aspx

Page 64: VSUG Day 2010 Summer - Using ADO.NET Entity Framework

VSUG DAY 2010.05.09

Page 65: VSUG Day 2010 Summer - Using ADO.NET Entity Framework

VSUG DAY 2010.05.09

Appendix

Page 66: VSUG Day 2010 Summer - Using ADO.NET Entity Framework

VSUG DAY 2010.05.09

EdmGen.exe

コマンドラインによるオブジェクト レイヤ生成

C#のコード生成

"%windir%¥Microsoft.NET¥Framework¥v4.0.30319¥edmgen.exe"

/mode:EntityClassGeneration

/incsdl:.¥School.csdl /outobjectlayer:.¥School.Objects.cs /language:CSharp

VBのコード生成

"%windir%¥Microsoft.NET¥Framework¥v4.0.30319¥edmgen.exe"

/mode:EntityClassGeneration

/incsdl:.¥School.csdl /outobjectlayer:.¥School.Objects.vb /language:VB

Page 67: VSUG Day 2010 Summer - Using ADO.NET Entity Framework

VSUG DAY 2010.05.09

概念スキーマ 定義言語: EntityContainer

<EntityContainer Name="ChinookEntities“

annotation:LazyLoadingEnabled="true">

<EntitySet Name="Albums"

EntityType="ChinookModel.Album" />

<EntitySet Name="Artists"

EntityType="ChinookModel.Artist" />

<AssociationSet Name="FK__Album__ArtistId__108B795B“

Association="ChinookModel.FK__Album__ArtistId__108B795B"

>

<End Role="Artist" EntitySet="Artists" />

<End Role="Album" EntitySet="Albums" />

</AssociationSet>

</EntityContainer>

Page 68: VSUG Day 2010 Summer - Using ADO.NET Entity Framework

VSUG DAY 2010.05.09

概念スキーマ 定義言語: EntityType

<EntityType Name="Album">

<Key>

<PropertyRef Name="AlbumId" />

</Key>

<Property Name="AlbumId" Type="Int32" Nullable="false"

annotation:StoreGeneratedPattern="Identity" />

<Property Name="Title" Type="String" Nullable="false"

MaxLength="160" Unicode="true" FixedLength="false" />

<Property Name="ArtistId" Type="Int32" Nullable="false" />

<NavigationProperty Name="Artist“

Relationship="ChinookModel.FK__Album__ArtistId__108B795B“

FromRole="Album" ToRole="Artist" />

</EntityType>

Page 69: VSUG Day 2010 Summer - Using ADO.NET Entity Framework

VSUG DAY 2010.05.09

概念スキーマ 定義言語: Association

<Association Name="FK__Album__ArtistId__108B795B">

<End Type="ChinookModel.Artist" Role="Artist"

Multiplicity="1" />

<End Type="ChinookModel.Album" Role="Album"

Multiplicity="*" />

<ReferentialConstraint>

<Principal Role="Artist">

<PropertyRef Name="ArtistId" />

</Principal>

<Dependent Role="Album">

<PropertyRef Name="ArtistId" />

</Dependent>

</ReferentialConstraint>

</Association>

Page 70: VSUG Day 2010 Summer - Using ADO.NET Entity Framework

VSUG DAY 2010.05.09

ストア スキーマ 定義言語: EntityContainer

<EntityContainer Name="ChinookModelStoreContainer">

<EntitySet Name="Album“

EntityType="ChinookModel.Store.Album"

store:Type="Tables" Schema="dbo" />

<EntitySet Name="Artist"

EntityType="ChinookModel.Store.Artist"

store:Type="Tables" Schema="dbo" />

<AssociationSet Name="FK__Album__ArtistId__108B795B"

Association="ChinookModel.Store.FK__Album__ArtistId__108B7

95B">

<End Role="Artist" EntitySet="Artist" />

<End Role="Album" EntitySet="Album" />

</AssociationSet>

</EntityContainer>

Page 71: VSUG Day 2010 Summer - Using ADO.NET Entity Framework

VSUG DAY 2010.05.09

ストア スキーマ 定義言語: EntityType

<EntityType Name="Album">

<Key><PropertyRef Name="AlbumId" /></Key>

<Property Name="AlbumId" Type="int" Nullable="false"

StoreGeneratedPattern="Identity" />

<Property Name="Title" Type="nvarchar"

Nullable="false" MaxLength="160" />

<Property Name="ArtistId" Type="int" Nullable="false" />

</EntityType>

<EntityType Name="Artist">

<Key><PropertyRef Name="ArtistId" /></Key>

<Property Name="ArtistId" Type="int" Nullable="false"

StoreGeneratedPattern="Identity" />

<Property Name="Name" Type="nvarchar" MaxLength="120" />

</EntityType>

Page 72: VSUG Day 2010 Summer - Using ADO.NET Entity Framework

VSUG DAY 2010.05.09

ストア スキーマ 定義言語: Association

<Association Name="FK__Album__ArtistId__108B795B">

<End Role="Artist" Type="ChinookModel.Store.Artist"

Multiplicity="1" />

<End Role="Album" Type="ChinookModel.Store.Album"

Multiplicity="*" />

<ReferentialConstraint>

<Principal Role="Artist">

<PropertyRef Name="ArtistId" />

</Principal>

<Dependent Role="Album">

<PropertyRef Name="ArtistId" />

</Dependent>

</ReferentialConstraint>

</Association>

Page 73: VSUG Day 2010 Summer - Using ADO.NET Entity Framework

VSUG DAY 2010.05.09

マッピング 仕様言語: EntityMapping

<EntitySetMapping Name="Albums">

<EntityTypeMapping

TypeName="ChinookModel.Album">

<MappingFragment

StoreEntitySet="Album">

<ScalarProperty Name="AlbumId" ColumnName="AlbumId" />

<ScalarProperty Name="Title" ColumnName="Title" />

<ScalarProperty Name="ArtistId" ColumnName="ArtistId" />

</MappingFragment>

</EntityTypeMapping>

</EntitySetMapping>

Page 74: VSUG Day 2010 Summer - Using ADO.NET Entity Framework

VSUG DAY 2010.05.09

データベースへの接続

以下の場合に自動的に接続

ObjectContext に対する SaveChanges()、または

Refresh(RefreshMode, IEnumerable)

ObjectQuery に対する FirstOrDefault(IEnumerable<UMP>)、または First(IEnumerable<UMP>)

EntityCollection に対する Load(MergeOption)

EntityReference に対する Load(MergeOption)

任意の統合言語クエリ (LINQ) メソッドまたは ObjectQuery クエリ ビルダー メソッド (Where(String, ObjectParameter[])、OrderBy(String, ObjectParameter[])、Select(String,

ObjectParameter[]) など)

接続は、ObjectResult が完全に消費されるか破棄されるまで開いたままになる

Page 75: VSUG Day 2010 Summer - Using ADO.NET Entity Framework

VSUG DAY 2010.05.09

接続を手動で開く

using (AdventureWorksEntities advWorksContext = new AdventureWorksEntities())

{

try { //明示的に接続を開く

advWorksContext.Connection.Open(); // オーダーを返すクエリを実行

SalesOrderHeader order = advWorksContext.SalesOrderHeaders.Where(

"it.SalesOrderID = @orderId", new ObjectParameter("orderId", orderId))

.Execute(MergeOption.AppendOnly).First();

order.Status = 1; // 変更を保存

if (0 < advWorksContext.SaveChanges())

{

Console.WriteLine("Changes saved.");

}

}

catch (InvalidOperationException ex) {

Console.WriteLine(ex.ToString());

} // オブジェクト コンテキストがDisposeされるときに接続は閉じられる

}