Hibernate中any元素的应用体会
关联(Associations)是Hibernate核心概念之一比较常用的有
manytoone onetoone onetomany manytomany
Hibernate还提供了另外一种关联——异类关联(Heterogeneous Associations)
在Hibernate Reference (cn) 中是这样说明的
引用:
异类关联(Heterogeneous Associations)
<manytoany>和<indexmanytoany>元素提供真正的异类关联这些元素和<any>元素工作方式是同样的他们都应该很少用到
下面针对<any>元素谈一些自己的体会
一什么时候需要<any>元素
持久类中一个属性关联另外一个指定的持久类(几乎每个应用都有这种情况)多半会使用manytoone onetoone这样的关联映射到关系数据库中也多半使用外键约束
可能会遇到有这么一种特殊的情况需要持久类中一个属性关联另外一些持久类
举个例子Log类中使用logEntity属性关联一组业务持久类(也就是说在Log中记录不同业务类的实例对象)
如果使用manytoone则有很大的限制首先需要这些业务类都要继承一个超类而且在数据库中必须有这个超类对应的表在Hibernate提供的三种继承映射策略中只能使用前两种
每棵类继承树使用一个表(table per class hierarchy)
每个子类一个表(table per subclass)
第种通常不大合适所有的业务类映射为一张表冗余过多限制也多增加一个业务类就需要修改表结构不易扩展
第种的情况是表的数量=业务表数量 + 一个超类表子类表通过主键和超类表关联(所以实际上关系模型是一对一关联)业务表数量比较多的时候这种结构的性能和灵活性都有问题
这时<any>元素就派上用场啦
二<any>元素的应用
类
业务类
java代码:
public class BizOne {
private Longid;
private StringbizOneDescription;
//Getters and Setters 省略
}
public class BizTwo {
private Longid;
private StringbizTwoDescription;
private DatecreateDate;
//Getters and Setters 省略
}
日志类
java代码:
public class MyLog {
private Longid;
private DatelogDate;
private ObjectlogEntity;//这就是<any>元素对应的属性
//Getters and Setter 省略
}
hbmxml 和 表结构
这里只给出MyLog的hbmxml(BizOne BizTwo很简单不提了)
java代码:
<hibernatemapping>
<class name=comtestentityMyLog table=MyLog>
<id name=id column=id>
<generator class=native/>
</id>
<property name=logDate/>
<any name=logEntity metatype=string idtype=long>
<metavalue value=One class=comtestentityBizOne/>
<metavalue value=Two class=comtestentityBizTwo/>
<column name=entityMetaValue length= />
<column name=entityId/>
</any>
</class>
</hibernatemapping>
表结构(MySQL)
java代码:
create table MyLog (
id BIGINT NOT NULL AUTO_INCREMENT
logDate datetime
entityMetaValue VARCHAR()
entityId BIGINT
primary key (id)
)
对<any>元素中子元素和属性的理解可以结合生成的表结构及其表中的数据(见)
name: 是持久类中属性名称
metatype: 是下面metavalue元素中value的类型如stringcharacter等
idtype: 是引用类的主键类型
metavalue元素中value: 该值将保存到数据库表中用来标识其后的class即引用的持久类请参考下面的数据
metavalue元素中class: 引用持久类的类全称
第一个column: 保存上面value值的字段
第二个column: 保存引用持久类的主键值的字段它的类型是idtype对应到数据库中的字段类型
记录日志的方法
java代码:
public MyLog recordLog(Object biz){
MyLog log = new MyLog();
logsetLogDate(new Date());
logsetLogEntity(biz);//引用了传递过来的业务对象
return getLogService()save(log);//保存log我习惯用Spring+Hibernate
}
Hibernate所保存的数据是这样
引用:
idlogDateentityMetaValueentityId
::One
::Two
::One
::Two
::Two
读取Log
java代码:
public MyLog readLog(Long id){
MyLog log = getLogService()getLog(id);
Object biz = loggetLogEntity();
//
return log;
}
用<any>所实现的关联与<manytoone>等关联的效果是相同的例如如果BizOne BizTwo的lazy=true则biz是个代理
BizThree如果增加了一个业务类BizThree在MyLoghbmxml中只需增加一行
java代码:
<metavalue value=Three class=comtestentityBizThree/>
限制
在<any>元素中需要指定idtype这可能是<any>对所关联类的唯一限制了所关联的类的主键类型必须相同
三再谈继承映射策略问题
上面提到了如果为了让Log能够关联业务类就要求业务类都要继承同一个超类是不大合适的不过不合适的理由在于这个超类需要在数据库有相应的表不能说业务类不能继承一个超类实际上很多应用中的业务类都有超类而且根据情况实现一些接口此时的继承映射策略是Hibernate Reference中的第三种每个具体类一个表(table per concrete class)上面MyLog中的logEntity的类型可以是更有意义的超类如Entity当然也可以是接口不必是Object这样即使超类在数据库中没有对应的表照样可以实现关联
四彩票
Hibernate Reference中提到<any>元素的地方不是很多但提到时总不忘记说应该很少用到应该在非常特殊的情况下使用它可能从全世界的角度看使用<any>是低概率事件但是如果遇到了就是%的概率了因此当你应用<any>的时候别忘了购买彩票因为与中奖同样的低概率事件——使用<any>——你已经碰到了你的运气就来了赶快买彩票吧准能中奖!