数据库通常包含许多表,这些表之间的关系通过主键和外键来实现。当定义业务实体以在 .NET 应用程序中表示这些数据时,必须确定如何把这些表映射到业务实体。
请考虑图 3 所示的假想零售商数据库。
图 3:假想的关系数据库中的表关系
下表总结了示例数据库中的关系类型。
关系类型 | 示例 | 说明 |
---|---|---|
一对多 | Customer:Address Customer:Order |
一个客户可以有多个地址,例如送货地址、帐单接收地址、联系地址等。 一个客户可以有多个订单。 |
多对多 | Order:Product | 一个订单可以包含许多产品,每种产品由 OrderDetails 表中的单独一行表示。同样,一种产品也可以出现在许多订单中。 |
当定义业务实体以在数据库中建立信息模型时,应考虑要如何在您的应用程序中使用这些信息。应当标识封装您的应用程序的功能的核心业务实体,而不是为每个表定义单独的业务实体。
该假想零售商的应用程序中的典型操作如下:
- 获取(或更新)客户的有关信息(包括地址)
- 获取客户的订单列表
- 获取特定订单的订购项目列表
- 创建新订单
- 获取(或更新)一个或一组产品的有关信息
为满足这些应用程序要求,该应用程序要处理三个逻辑业务实体:Customer、Order 和 Product。对于每个业务实体,都将定义一个单独的数据访问逻辑组件,如下所示:
- Customer 数据访问逻辑组件。此类将为检索和修改 Customer 表和 Address 表中的数据提供服务。
- Order 数据访问逻辑组件。此类将为检索和修改 Order 表和 OrderDetails 表中的数据提供服务。
- Product 数据访问逻辑组件。此类将为检索和修改 Product 表中的数据提供服务。
图 4 所示为这些数据访问逻辑组件与它们所表示的数据库中的表之间的关系。
图 4:定义向 .NET 应用程序公开关系数据的数据访问逻辑组件
将关系数据映射到业务实体的建议
要将关系数据映射到业务实体,请考虑以下建议:
- 花些时间来分析您的应用程序的逻辑业务实体并为之建立模型,不要为每个表定义一个单独的业务实体。建立应用程序的工作方式模型的方法之一是使用统一建模语言 (UML)。UML 是一种形式设计注释,用于在面向对象的应用程序中建立对象模型,并获取有关对象如何表示自动过程、人机交互以及关联的信息。
- 不要定义单独的业务实体来表示数据库中的多对多表,可以通过在数据访问逻辑组件中实现的方法来公开这些关系。例如,前面示例中的 OrderDetails 表没有映射到单独的业务实体,而是通过在 Order 数据访问逻辑组件中封装 OrderDetails 表来实现 Order 与 Product 表之间的多对多关系。
- 如果具有返回特定业务实体类型的方法,请把这些方法放在该类型对应的数据访问逻辑组件中。例如,当检索一个客户的全部订单时,返回值为 Order 类型,因此应在 Order 数据访问逻辑组件中实现该功能。反之,当检索订购某特定产品的全部客户时,应在 Customer 数据访问逻辑组件中实现该功能。
- 数据访问逻辑组件通常访问来自单一数据源的数据。当需要聚合多个数据源的数据时,建议分别为访问每个数据源定义一个数据访问逻辑组件,这些组件可以由一个能够执行聚合任务的更高级业务过程组件来调用。建议采用这种方法的原因有二:
- 事务管理集中在业务过程组件中,不需要由数据访问逻辑组件显式控制。如果通过一个数据访问逻辑组件访问多个数据源,则需要把该数据访问逻辑组件作为事务处理的根,这会给仅读取数据的功能带来额外的系统开销。
- 通常,并不是应用程序的所有区域都需要聚合,并且通过分离对数据的访问,您可以单独使用该类型,也可以在必要时将其用作聚合的一部分。
数据访问逻辑组件是一个无状态类,也就是说,所交换的所有消息都可以独立解释。调用之间不存在状态。数据访问逻辑组件为访问单一数据库(某些情况下可以是多个数据库,例如水平数据库分区)中的一个或多个相关表提供方法。通常,数据访问逻辑组件中的这些方法将调用存储过程以执行相应操作。
数据访问逻辑组件的主要目标之一是从调用应用程序中隐藏数据库的调用及格式特性。数据访问逻辑组件为这些应用程序提供封装的数据访问服务。具体地说,数据访问逻辑组件处理以下实现细节:
- 管理和封装锁定模式
- 正确处理安全性和授权问题
- 正确处理事务处理问题
- 执行数据分页
- 必要时执行数据相关路由
- 为非事务性数据的查询实现缓存策略(如果适用)
- 执行数据流处理和数据序列化
本节后面将详细讨论其中的某些问题。
数据访问逻辑组件的应用方案图 5 所示为从各种应用程序类型(包括 Windows 窗体应用程序、ASP.NET 应用程序、XML Web services 和业务过程)中调用数据访问逻辑组件的方式。根据应用程序的部署方式,这些调用可以是本地的,也可以是远程的。