数据模型(ADO.NET 数据服务框架)

ADO.NET 数据服务本机支持 ADO.NET 实体框架模型,并提供一个扩展,通过此扩展可使用公共语言运行库 (CLR) 对象定义数据模型。实体数据模型 (EDM) 的术语,具体而言有概念架构定义语言 (CSDL) 和 EntitySetEntityTypePropertyAssociationAssociationSet 等术语,可用于描述 ADO.NET 数据服务架构部署的数据。有关这些术语的定义,请参见 ADO.NET 数据服务框架术语。有关 CSDL 的更多信息,请参见 EDM 规范

通过将数据源简化为单一语法和统一的 URI 约定,不管基础数据源如何,ADO.NET 数据服务都可以部署数据的一致表示形式。在使用实体框架模型时,设置数据服务并不重要。对于基于 CLR 的模型,已在 CLR 对象和 EDM 类型之间定义一个映射。

EDM 数据模型

在实体数据模型 (EDM) 中,ADO.NET 数据服务将与实体架构的对象服务层进行交互,此层是一个 CLR 可编程上下文。虽然可以手动创建编程上下文和概念模型,但建议使用与 Microsoft Visual Studio 2008(从 SP1 开始)集成的实体数据模型工具

有关使用 EDM 和实体框架工具的示例,请参见数据服务快速入门(ADO.NET 数据服务框架)

基于 CLR 的数据模型

ADO.NET 数据服务的工作方式是将 URI 请求转换为对通过 URI 语法寻址的数据进行的操作。若数据模型基于实体框架,则 URI 将转换为对象服务方法调用。实体框架 ObjectContext 基于 ObjectQuery<T> 部署数据集,而 ObjectQuery<T> 将实现 IQueryable<T>

通过实现 IQueryable 的派生项来部署其数据的任何技术或数据提供程序均可作为 ADO.NET 数据服务进行部署。自 .NET Framework 3.5 开始提供的 AsQueryable 扩展方法可与实现 IEnumerable<T> 的对象一起使用。.NET Framework 中所有实现 IEnumerable<T> 的类都可以通过调用 AsQueryable 扩展方法来进行扩展。这意味着,可以将大多数列表、数组和集合有效地作为 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 类型(如上一个代码中的注释中所示)。

实体容器和实体集

  • 显式定义的命名空间中的单个公共 CLR 类 (C1) 用于定义模型中所有顶级实体集。通过使用 URI 中的第一个路径段,可以访问顶级资源。

  • 类 C1 所在的命名空间是一个将 C1 标识为实体容器的命名空间。即使 C1 为派生类型,这也保持不变。

  • 类 C1 的名称表示实体容器。可以为命名空间定义单个实体容器。即使 C1 为派生类型,这也保持不变。

  • 必须将每个实体集表示为类 C1 的一个公共属性 (P1) 并且其返回类型为 IQueryable<T>。类 C1 或其某个父类(如果类 C1 为派生类型)上可能存在零个或多个此类属性。

    • T 表示实体集中的实体类型。

    • T 必须具有一个适合作为实体键的属性,以便将属性 C1 视为实体集。如果不存在此类适合的键属性,则 ADO.NET 数据服务将跳过属性 P1,并且不会考虑用 C1 表示实体集。

    • 类 C1 或其父类上的多个属性不能返回同一类型 T。此基于 CLR 的模型定义不支持在多个实体集中包含同一实体类型(在本示例中,类 T 表示实体类型)。在实体框架中,可以为每个类型实现多个实体集,但不能作为由 ADO.NET 数据服务部署的类实现。

实体类型、属性和导航链接

  • 一个公共 CLR 类 (C1) 表示一个实体类型。

  • 若要将一个类识别为实体类型,该类必须具有一个或多个表示类型的键的属性。此类属性或属性组将成为实体类型的键。表示键的属性的规则包括:

    • 名为 ID 的公共属性。

    • 名为 <className>ID 的公共属性。

    • DataWebKeyAttribute 属性 (Attribute) 标记的公共属性 (Property)。

    • 如果一个类包含用 DataWebKeyAttribute 标记的一个属性 (Property) 或属性 (Property) 组,则这些属性 (Property) 将用作键,并且前两个规则将被忽略。如果任何属性 (Property) 都不包含此属性 (Attribute),则与前两个规则匹配的那些属性 (Property) 将决定实体类型的键属性 (Property)。如果有多个属性 (Property) 与规则匹配,则根据定义,实体类型具有一个组合键。

  • 如果类 C1 是层次结构的一部分,则通过应用以下规则将类层次结构转换为实体类型层次结构:

    • 最靠近类层次结构的根部且包含有效键属性的 CLR 类将成为实体类型层次机构的根。如果类 C1 不是其所在的 CLR 类层次结构的根,则将层次结构中位于 C1 上方的类所声明的属性假定为由 C1 声明。
  • 如果 CLR 属性符合下列所有约定,则将类 C1 声明的每个属性 (P) 转换为实体类型上的属性:

    • CLR 属性必须具有公共范围。

    • CLR 属性必须实现该属性的 get 方法。

    • CLR 属性不得为一个索引器。

    • 如果属性 P 的返回类型为一个基元类型,并且此类型与 EDM 类型相对应,则必须将属性 P 表示为某个属性。有关 EDM 类型到 CLR 类型的映射,请参见 ADO.NET 数据服务内容类型

    • 如果属性 P 的返回类型为一个引用类型,并且此类型或其父对象之一(如果此类型为派生类型)表示一个实体类型,则 P 表示一个一对一的导航链接。

    • 如果属性 P 的返回类型为 IEnumerable<T>,并且 T 表示一个实体类型,则 P 表示一个一对多的导航链接。

    • 如果属性 P 的返回类型为一个值类型,则 P 表示一个复杂类型。

复杂类型

  • 一个公共 CLR 值类型 (V1) 表示一个复杂类型。

  • 值类型 V1 的每个属性将转换为一个复杂类型的属性。复杂类型遵循与实体类型相似的规则,以确定是否将 CLR 属性映射到某个属性。

    • CLR 属性必须具有公共范围。

    • CLR 属性必须实现该属性的 Get 方法。

    • CLR 属性不得为一个索引器。

    • 如果属性 P 的返回类型为一个引用类型,并且此类型或其父对象之一(如果此类型为派生类型)表示一个实体类型,则 P 表示一个一对一的导航链接。

示例 2:CLR 类到 ADO.NET 数据服务资源

下面的示例演示 CLR 类,此类包含用于实现 ADO.NET 数据服务资源类型的继承。

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 数据服务规范

其他资源

实体数据模型