目的
为了在内存对象和数据库行之间维护标识而在对象内保存的一个数据库标识域。
关系数据库和内存对象的区别
-
区分行:关系数据库使用键来区分数据行,而内存对象不需要这样一个键
-
引用方法:对象系统中通过原始内存位置直接区分对象,数据库需要键区分行
因此,为了满足对数据库的几个基本操作,对象和数据库行之间依靠标识域进行交互。
工作机制
键的选择
两类键:
- 有意义的键:含有语义的键,如身份证号码,容易出现错误。
- 无意义的键:数据库顺序码。数据库系统自行维护,不会出现错误。
复杂程度:
- 简单键:只使用一个数据库域
- 组合键:使用数据库多个域
唯一性:
- 表唯一键:在一个表中是唯一的。
- 数据库唯一键:对任何表的任何数据行都是唯一的。
标识域的处理
- 简单键:比如使用一个简单的整数键即可,并且容易做等值比较。
- 组合键:等值比较复杂些,需要单独一个类来处理-键类。
标识域的表示
- 采用基本结构表示标识域共同特征,不同的情况在子类中处理。
- 只用一个单独的键类,维护一个键对象的普通列表。
- 每一个领域类对应一个键类。
创建新键
- 自动生成,但要依赖于不同数据库系统提供的不同功能。
- 自动生成域。缺点是:难以确定生成什么键值,如插入一份订单以及多个订单项。
- 数据库计数器。如Oracle的序列,可以让序列以任何整数增长,但没有统一标准。
- GUID(全局唯一标识符),缺点:生成算法使用了以太网卡地址、纳秒级的时钟、芯片ID码和其他可能的数字,生成的结果串比较大。
- 自己产生键值。利用算法找到表中的最大项。
- 键表。包含两列:名字和下一个有效值,如果使用表唯一键,对于数据库中每一个表都有一行数据与之对应,如果使用数据库唯一键,只有一行数据与之对应。
使用时机
- 一般在使用领域模型或者行数据入口时使用;
- 在事务脚本、表模块或者表数据入口不需要;
- 对于有值语义的小对象,如货币或者日期范围等自身不构成表的对象,最好使用嵌入值
- 还可以扩展标识映射来维护标识域,一般用于不便在内存对象中保存标识域的系统中
示例之一-使用整型键(C#)
键在两种情况下很重要:查找和插入。
查找分为两步:加载多行到一个数据集中;查找选出特定的记录。
插入。使用简单的整数标识域,插入行为可以层超类型上实现
示例之二-使用键表(Java)
创建单独的键产生器
示例之三-使用组合键(Java)
组合键的处理最好采用键类,应具有存储键中多元素并且能判断两键相等
领域对象的层超类型需要一个键域
示例之四-使用组合键(Java)
读取订单及订单项。分为查找(找到正确的行)和加载(从行中加载到领域对象),本例的思想:把单键,即整型键的行为作为默认的情形,子类可以覆盖该默认行为。
读取订单及订单项。分为查找(找到正确的行)和加载(从行中加载到领域对象)。
订单和订单项分别用具体的行为覆盖层超类型中的方法
插入订单及订单项(更新和删除操作类似)。
本例的思想:对于单键,即整型键的行为作为默认的情形,子类可以覆盖该默认行为。
同时把键数据和对象中的数据分开插入,因为可以为键提供默认行为。