共用方式為


資料模型 (ADO.NET 資料服務架構)

ADO.NET 資料服務原本就支援 ADO.NET Entity Framework 模型,並且提供了可以使用 Common Language Runtime (CLR) 物件來定義資料模型的擴充功能。Entity Data Model (EDM) 的術語 (明確地說,概念結構定義語言 (CSDL)) 以及 EntitySetEntityTypePropertyAssociationAssociationSet 等詞彙可用於描述 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 介面。

另請參閱

概念

ADO.NET 資料服務規格

其他資源

Entity Data Model