ADO.NET 資料服務原本就支援 ADO.NET Entity Framework 模型,並且提供了可以使用 Common Language Runtime (CLR) 物件來定義資料模型的擴充功能。Entity Data Model (EDM) 的術語 (明確地說,概念結構定義語言 (CSDL)) 以及 EntitySet、EntityType、Property、Association、AssociationSet 等詞彙可用於描述 ADO.NET 資料服務架構所部署的資料。如需這些詞彙的定義,請參閱 ADO.NET 資料服務架構術語。如需 CSDL 的詳細資訊,請參閱 EDM 規格。
透過減少單一文法和統一 URI 慣例的資料來源,不論基礎資料來源為何,ADO.NET 資料服務都可以部署一致的資料表示。使用 Entity Framework 模型時,設定資料服務是一般作業。若為以 CLR 為基礎的方法,CLR 物件與 EDM 型別之間的對應已經定義。
EDM 資料模型
在 Entity Data Model (EDM) 中,ADO.NET 資料服務會與 Entity Framework 的物件服務層 (CLR 可程式化內容) 互動。雖然您可以手動建立程式設計內容和概念模型,不過建議的方法是使用與 Microsoft Visual Studio 2008 (從 SP1 開始) 整合的 Entity Data Model 工具。
如需使用 EDM 和 Entity Framework 工具的範例,請參閱資料服務快速入門 (ADO.NET 資料服務架構)。
以 CLR 為基礎的資料模型
ADO.NET 資料服務的運作方式是將 URI 要求轉換成 URI 語法所定址之資料的作業。當資料模型是以 Entity Framework 為基礎時,URI 就會轉換成物件服務方法呼叫。Entity Framework ObjectContext 會部署以 ObjectQuery<T> 為基礎的資料集,而 ObjectQuery<T> 會實作 IQueryable<T>。
任何透過實作 IQueryable 之衍生來部署其資料的技術或資料提供者 (Data Provider) 都可以部署成 ADO.NET 資料服務。從 .NET Framework 3.5 開始提供的 AsQueryable 擴充方法可以搭配實作 IEnumerable<T> 的物件使用。您可以呼叫 AsQueryable 擴充方法來擴充 .NET Framework 中實作 IEnumerable<T> 的所有類別 (Class)。這表示,大部分清單、陣列和集合都可以有效率地部署成 ADO.NET 資料服務。
LINQ 查詢也會使用實作 IEnumerable<T> 或 IQueryable<T> 的資料來源。當您使用 CLR 物件來定義 ADO.NET 資料服務的基礎資料模型時,要求 URI 就會轉換成 LINQ 查詢。完整的對應會定義在 CLR 物件與 ADO.NET 資料服務資源之間。CLR 物件與 ADO.NET 實體集的對應可讓 ADO.NET 資料服務部署任何可讀入記憶體當做陣列、清單或集合的資料來源。
範例 1:CLR 類別與 ADO.NET 資料服務資源
下列範例將顯示 CLR 建構與 ADO.NET 資料服務資源之間的對應。實作 IQueryable<T> 介面的類別會表示成實體集。
下列範例會使用 AsQueryable 擴充方法,將 Customers 的陣列轉換成 IQueryable<T> 格式。雖然 Customers 的陣列在此以簡單方式建構,不過您幾乎可以從任何來源讀取應用程式資料。
此程式碼範例會加上附註,指出 CLR 型別如何對應至 ADO.NET 資料服務資源類型。
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 資料服務資源時,相關聯的 ADO.NET 資料服務資源會複製 CLR 名稱的大小寫。下列清單將描述對應至 ADO.NET 資料服務資源的 CLR 型別 (如上述程式碼的註解所示)。
實體容器和實體集
明確定義之命名空間 (Namespace) 內的單一公用 (Public) CLR 類別 (C1) 是用於定義模型中的所有最上層實體集。您可以使用 URI 中的第一個路徑區段來存取最上層資源。
類別 C1 所在的命名空間就是將 C1 識別為實體容器的命名空間。即使 C1 是衍生型別 (Derived Type),這仍然是固定行為。
類別 C1 的名稱代表實體容器。您可以針對此命名空間定義單一實體容器。即使 C1 是衍生型別,這仍然是固定行為。
每個實體集都必須表示成傳回型別為 IQueryable<T> 之類別 C1 的公用屬性 (P1)。零或多個這類屬性可能會存在類別 C1 上 (如果此類別是衍生型別的話),或存在其中一個父類別上。
T 代表實體集內部的實體類型。
T 必須具有適合當做實體索引鍵的屬性,才能讓屬性 C1 被視為實體集。如果這類適合的索引鍵屬性不存在,ADO.NET 資料服務就會略過屬性 P1 而且不會將 C1 視為代表實體集。
相同的類型 T 無法由類別 C1 或 C1 父類別的多個屬性傳回。這個以 CLR 為基礎的模型定義不支援在多個實體集中包含相同的實體類型 (在此情況下,由類別 T 表示)。每個類型的多重實體可以在 Entity Framework 中實作,但是無法實作成 ADO.NET 資料服務所部署的類別。
實體類型、屬性和導覽連結
公用 CLR 類別 (C1) 代表實體類型。
若要被辨識成實體類型,類別必須具有代表該類型之索引鍵的一或多個屬性。這類屬性或屬性群組會成為實體類型的索引鍵。代表索引鍵之屬性的規則如下:
名為 ID 的公用屬性。
名為 <className>ID 的公用屬性。
以 DataWebKeyAttribute 屬性 (Attribute) 標記的公用屬性 (Property)。
如果某個類別包含以 DataWebKeyAttribute 標記的屬性或屬性群組,這些屬性就會當做索引鍵使用,而且忽略前兩個規則。如果沒有任何屬性 (Property) 包含該屬性 (Attribute),符合前兩個規則的這些屬性 (Property) 就會決定實體類型的索引鍵屬性。如果多個屬性符合這些規則,實體類型就會依照定義具有複合索引鍵。
如果類別 C1 屬於階層的一部分,此類別階層就會透過套用下列規則,轉譯成實體類型階層:
- 最接近包含有效索引鍵屬性之類別階層根 (Root) 的 CLR 類別會成為實體類型階層的根。如果類別 C1 不是它所參與之 CLR 類別階層的根,則階層中 C1 以上之類別所宣告的屬性都會被視為由 C1 所宣告。
如果 CLR 屬性符合下列所有慣例,類別 C1 所宣告的每個屬性 (P) 都會轉譯成實體類型的屬性:
CLR 屬性必須具有公用範圍。
CLR 屬性必須實作屬性的 Get 方法。
CLR 屬性不得為索引子 (Indexer)。
如果屬性 P 的傳回型別是基本型別 (Primitive Type),而且此型別對應至 EDM 型別,該屬性就必須表示成屬性。如需 EDM 型別與 CLR 型別的對應,請參閱 ADO.NET 資料服務內容類型。
如果屬性 P 的傳回型別是參考型別 (Reference Type),而且此型別或其中一個父物件 (如果它是衍生型別的話) 代表實體類型,則 P 就代表 (1-1) 導覽連結。
如果屬性 P 的傳回型別是 IEnumerable<T>,而且 T 代表實體類型,則 P 就代表一對多導覽連結。
如果屬性 P 的傳回型別是實值型別 (Value Type),則 P 就代表複雜類型。
複雜類型
公用 CLR 實值型別 (V1) 代表複雜類型。
實值型別 V1 的每個屬性都會轉譯成複雜類型的屬性。複雜類型會遵循類似於實體類型的規則來判斷 CLR 屬性是否會對應至屬性。
CLR 屬性必須具有公用範圍。
CLR 屬性必須實作屬性的 Get 方法。
CLR 屬性不得為索引子。
如果屬性 P 的傳回型別是參考型別,而且此型別或其中一個父物件 (如果它是衍生型別的話) 代表實體類型,P 就代表一對一導覽連結。
範例 2:CLR 類別與 ADO.NET 資料服務資源
下列範例將顯示包含用於實作 ADO.NET 資料服務資源類型之繼承 (Inheritance) 的 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 資料服務架構資源」而言,Accounting.DataModel 類別必須實作 IUpdatable 介面。