ADO.NET Data Services は、ADO.NET Entity Framework モデルをネイティブでサポートしており、共通言語ランタイム (CLR) オブジェクトを使用してデータ モデルを定義できる拡張機能を提供しています。ADO.NET Data Services フレームワークによって配置されるデータの記述には、エンティティ データ モデル (EDM)、特に概念スキーマ定義言語 (CSDL) の用語や、EntitySet、EntityType、Property、Association、AssociationSet などの用語が使用されます。これらの用語の定義については、「ADO.NET Data Services フレームワークの用語」を参照してください。CSDL の詳細については、「EDM 仕様」を参照してください。
データ ソースに単一の文法および一貫した URI 規則を適用することで、ADO.NET Data Services は、基になるデータ ソースがどのようなものであっても、一貫した表現方法でデータを配置できます。エンティティ フレームワーク モデルを使用した場合、データ サービスは簡単に設定できます。CLR ベース モデルに対しては、CLR オブジェクトと EDM 型の間のマッピングが定義されています。
EDM データ モデル
エンティティ データ モデル (EDM) では、ADO.NET Data Services は CLR プログラミング コンテキストであるエンティティ フレームワークの Object Services 層と対話します。プログラミング コンテキストおよび概念モデルは手動で作成することもできますが、Microsoft Visual Studio 2008 SP1 以降と統合されているEntity Data Model ツールを使用することをお勧めします。
EDM およびエンティティ フレームワーク ツールを使用した例については、「データ サービスのクイック スタート (ADO.NET Data Services フレームワーク)」を参照してください。
CLR ベースのデータ モデル
ADO.NET Data Services は、URI 構文でアドレス指定されるデータに対する操作に URI 要求を変換することで処理を行います。データ モデルがエンティティ フレームワークに基づいている場合、URI は Object Services メソッド呼び出しに変換されます。エンティティ フレームワークの ObjectContext は ObjectQuery<T> に基づいてデータ セットを配置し、ObjectQuery<T> は IQueryable<T> を実装します。
IQueryable の派生物を実装することによってデータを配置するテクノロジまたはデータ プロバイダは、ADO.NET データ サービスとして配置できます。.NET Framework 3.5 以降で利用可能な AsQueryable 拡張メソッドは、IEnumerable<T> を実装するオブジェクトで使用できます。IEnumerable<T> を実装する .NET Framework 内のすべてのクラスは、AsQueryable 拡張メソッドを呼び出すことで拡張できます。つまり、ほとんどの一覧、配列、およびコレクションは、ADO.NET Data Services として効率的に配置できます。
LINQ クエリも IEnumerable<T> または IQueryable<T> を実装するデータ ソースで使用できます。ADO.NET Data Service の基になるデータ モデルを CLR オブジェクトを使用して定義する場合、要求の URI は LINQ クエリに変換されます。CLR オブジェクトと ADO.NET Data Services リソース間には完全なマッピングが定義されます。CLR オブジェクトから ADO.NET エンティティ セットへのマッピングによって、ADO.NET Data Services は、配列、一覧、またはコレクションとしてメモリに読み込むことのできる任意のデータ ソースを配置できます。
例 1: CLR クラスから ADO.NET Data Service リソースへのマッピング
次の例は、CLR コンストラクトと ADO.NET Data Services リソース間のマッピングを示しています。IQueryable<T> インターフェイスを実装するクラスは、エンティティ セットとして表されます。
次の例では、AsQueryable 拡張メソッドを使用して Customers
の配列を IQueryable<T> 形式に変換します。Customers
の配列はここでは単純に作成されていますが、アプリケーション データはほとんどすべてのソースから読み取ることができます。
コード例には、CLR 型から ADO.NET Data Services リソース型へのマッピング方法を示すために注釈が付けられています。
namespace Accounting // Namespace
{
public class DataModel // EntityContainer
{
public IQueryable<Customer> Customers // EntitySet
{
get
{
return new Customer[] { new Customer(1, "name1"),
new Customer(2,
"name2") }.AsQueryable<Customer>();
}
}
}
public class Customer // EntityType
{
private int _ID;
private string _name;
private Address _address;
public Customer(int i, string name)
{
_ID = i;
_name = name;
_address.Line1 = "Line" + i;
_address.Line2 = "Line" + i;
}
[DataWebKeyAttribute]
public int ID // Entity Type Key
{
get { return _ID; }
}
public string CustName // Property
{
get { return _name; }
}
public Address Address // Property
{
get { return _address; }
}
}
public struct Address // ComplexType
{
private string line1;
private string line2;
public string Line1 // Property
{
get { return this.line1; }
set { this.line1 = value; }
}
public string Line2 // Property
{
get { return this.line2; }
set { this.line2 = value; }
}
}
}
CLR エンティティから ADO.NET Data Services リソースにマッピングするとき、CLR 名の文字種は関連する ADO.NET Data Services リソースによってコピーされます。前のコード内でコメントで示されている、ADO.NET Data Services リソースに対応する CLR 型については、次の一覧で説明されています。
エンティティ コンテナとエンティティ セット
明示的に定義されている名前空間内の 1 つの CLR パブリック クラス (C1) が、モデル内の最上位レベルのエンティティ セットすべてを定義するために使用されます。最上位レベルのリソースには、URI の最初のパス セグメントを使用してアクセスできます。
クラス C1 が存在する名前空間は、C1 をエンティティ コンテナとして識別する名前空間です。これは C1 が派生型である場合も変わりません。
クラス C1 の名前はエンティティ コンテナを表します。名前空間に対しては 1 つのエンティティ コンテナを定義できます。これは C1 が派生型である場合も変わりません。
各エンティティ セットは、IQueryable<T> の戻り値の型を持つクラス C1 のパブリック プロパティ (P1) として表す必要があります。クラス C1 にはこのようなプロパティがいくつか存在する場合があります。クラスが派生型である場合は、その親クラスのいずれかに存在する場合があります。
T は、エンティティ セット内のエンティティ型を表します。
プロパティ C1 をエンティティ セットと見なすには、T がエンティティ キーに適したプロパティを持っている必要があります。適切なキー プロパティが存在しない場合、プロパティ P1 はスキップされ、ADO.NET Data Services データ サービスでは C1 をエンティティ セットとして見なしません。
クラス C1 または C1 の親クラスの複数のプロパティが同じ型 T を返すことはできません。CLR に基づいたこのモデル定義では、複数のエンティティ セット内での同じエンティティ型の使用をサポートしていません。この場合の型はクラス T で表されているものです。1 つの型に対する複数のエンティティ セットをエンティティ フレームワークに実装することはできますが、ADO.NET Data Services によって配置されているクラスとしては実装できません。
エンティティ型、プロパティ、およびナビゲーション リンク
CLR パブリック クラス (C1) は、エンティティ型を表します。
エンティティ型として認識されるには、型のキーを表す 1 つ以上のプロパティをクラスが保持している必要があります。このような 1 つのプロパティまたはプロパティのグループは、そのエンティティ型のキーになります。キーを表すプロパティの規則は次のとおりです。
ID という名前のパブリック プロパティ。
<className>ID という名前のパブリック プロパティ。
DataWebKeyAttribute 属性が設定されているパブリック プロパティ。
DataWebKeyAttribute が設定された 1 つのプロパティまたはプロパティのグループがクラスに含まれている場合は、これらのプロパティがキーとして使用され、最初の 2 つの規則は無視されます。属性を含むプロパティが存在しない場合は、最初の 2 つの規則に一致するプロパティがエンティティ型のキー プロパティを決定します。複数のプロパティが規則に一致する場合、エンティティ型は複合キーを持つものと定義されます。
クラス C1 が階層の一部である場合は、次の規則を適用することでクラス階層がエンティティ型階層に変換されます。
- 有効なキー プロパティを含むクラス階層のルートに最も近い CLR クラスがエンティティ型階層のルートになります。クラス C1 がその CLR クラス階層のルートでない場合は、階層内で C1 の上にあるクラスによって宣言されているプロパティが C1 によって宣言されているものと見なされます。
CLR プロパティが次の規則すべてに準拠している場合は、クラス C1 によって宣言されている各プロパティ (P) がエンティティ型のプロパティに変換されます。
CLR プロパティはパブリック スコープを持っている必要があります。
CLR プロパティはプロパティの GET メソッドを実装する必要があります。
CLR プロパティはインデクサでない必要があります。
プロパティ P の戻り値の型がプリミティブ型であり、その型が EDM 型に対応している場合は、そのプロパティを 1 つのプロパティとして表す必要があります。EDM 型から CLR 型へのマッピングについては、「ADO.NET Data Services のコンテンツの種類」を参照してください。
プロパティ P の戻り値の型が参照型であり、その型または親のオブジェクトのいずれか (それが派生型である場合) がエンティティ型を表す場合、P は 1 対 1 のナビゲーション リンクを表します。
プロパティ P の戻り値の型が IEnumerable<T> であり、T がエンティティ型を表す場合、P は 1 対多のナビゲーション リンクを表します。
プロパティ P の戻り値の型が値型である場合、P は複合型を表します。
複合型
CLR パブリック値型 (V1) は、複合型を表します。
値型 V1 の各プロパティは、複合型のプロパティに変換されます。複合型は、エンティティ型と同じような規則に従い、CLR プロパティがプロパティにマッピングされるかどうかを判断します。
CLR プロパティはパブリック スコープを持っている必要があります。
CLR プロパティはプロパティの GET メソッドを実装する必要があります。
CLR プロパティはインデクサでない必要があります。
プロパティ P の戻り値の型が参照型であり、その型または親のオブジェクトのいずれか (それが派生型である場合) がエンティティ型を表す場合、P は 1 対 1 のナビゲーション リンクを表します。
例 2: CLR クラスから ADO.NET Data Service リソースへのマッピング
次の例は、ADO.NET Data Services リソース型を実装するために使用される継承を含む CLR クラスを示しています。
namespace Accounting
{
public class DataModel
{
public IQueryable<Customer> Customers
{
get
{
return new Customer[] { new Customer(1, "name1"),
new Customer(2, "name2") }.AsQueryable<Customer>();
}
}
public IQueryable<Order> Orders
{
get
{
return new Order[] { new Order(1, "order1"),
new Order(2, "order2") }.AsQueryable<Order>();
}
}
}
public class DerivedDataModel : DataModel
{
public IQueryable<HumanResources.Employee> Employees
{
get { return new HumanResources.Employee[] { new
HumanResources.Employee(1, "EmpName1"), new
HumanResources.Employee(2, "EmpName2")
}.AsQueryable<HumanResources.Employee>();
}
}
}
public class Person
{
protected int _ID;
public Person() { }
public Person(int i)
{
_ID = i;
}
[DataWebKeyAttribute]
public int ID
{
get { return _ID; }
}
}
public class Customer : Person
{
private string _name;
private Address _address;
List<Order> _orders;
public Customer(int i, string name)
{
_ID = i;
_name = name;
_orders = new List<Order>();
if (i == 1) { _orders.Add(new Order(1, "order1")); }
if (i == 2) { _orders.Add(new Order(2, "order2")); }
_address.Line1 = "Line" + i;
_address.Line2 = "Line" + i;
}
public string CustName
{
get { return _name; }
}
public Address Address
{
get { return _address; }
}
public IList<Order> Orders
{
get { return _orders; }
}
}
public class Order
{
private int _ID;
private string _name;
public Order(int i, string name)
{
_ID = i;
_name = name;
}
[DataWebKeyAttribute]
public int OrderKey
{
get { return _ID; }
}
public string OrderName
{
get { return _name; }
}
}
public struct Address
{
private string line1;
private string line2;
public string Line1
{
get { return this.line1; }
set { this.line1 = value; }
}
public string Line2
{
get { return this.line2; }
set { this.line2 = value; }
}
}
}
namespace HumanResources
{
public class Employee
{
private int _ID;
private string _name;
public Employee(int i, string name)
{
_ID = i;
_name = name;
}
public int ID
{
get { return _ID; }
}
public string EmpName
{
get { return _name; }
}
}
}
書き込みと更新のサポート
CLR データ モデルでの作成、更新、削除のサポートを有効にするには、最上位レベルのエンティティ セットをモデル化するクラスで IUpdatable インターフェイスを実装する必要があります。上記の例 2 の、CLR オブジェクトから ADO.NET Data Services フレームワーク リソースへのマッピングに関しては、Accounting.DataModel クラスで IUpdatable インターフェイスを実装する必要があります。