Hibernate中any元素的应用体会

 

关联(Associations)是Hibernate核心概念之一,比较常用的有:

many-to-one, one-to-one, one-to-many, many-to-many

Hibernate还提供了另外一种关联——异类关联(Heterogeneous Associations)

在Hibernate Reference (cn) 2.1.6中是这样说明的:

引用
6.10. 异类关联(Heterogeneous Associations)
<many-to-any>和<index-many-to-any>元素提供真正的异类关联。这些元素和<any>元素工作方式是同样的,他们都应该很少用到。

 

下面针对<any>元素,谈一些自己的体会。

一、什么时候需要<any>元素

持久类中“一个属性”关联“另外一个指定的持久类”(几乎每个应用都有这种情况),多半会使用many-to-one, one-to-one这样的关联。映射到关系数据库中,也多半使用外键约束。

可能会遇到有这么一种特殊的情况,需要:持久类中“一个属性”关联“另外一些持久类”。

举个例子:Log类中使用logEntity属性关联一组业务持久类。(也就是说,在Log中记录不同业务类的实例对象)

如果使用many-to-one,则有很大的限制。首先,需要这些业务类都要继承一个超类,而且在数据库中必须有这个超类对应的表。在Hibernate提供的三种继承映射策略中,只能使用前两种:
1、“每棵类继承树使用一个表(table per class hierarchy) ”
2、“每个子类一个表(table per subclass)”

第1种通常不大合适:所有的业务类映射为一张表,冗余过多,限制也多,增加一个业务类就需要修改表结构,不易扩展。

第2种的情况是:表的数量=业务表数量 + 一个超类表,子类表通过主键和超类表关联(所以实际上关系模型是一对一关联)。业务表数量比较多的时候,这种结构的性能和灵活性都有问题。

这时<any>元素就派上用场啦。

二、<any>元素的应用

1、类:

业务类:

  public   class  BizOne  {
    
private Long    id;
    
private String    bizOneDescription;
    
//Getters and Setters 省略
}

public   class  BizTwo  {
    
private Long    id;
    
private String    bizTwoDescription;
    
private Date    createDate;
    
//Getters and Setters 省略
}

 日志类:

 

public   class  MyLog  {
    
private Long    id;
    
private Date    logDate;
    
private Object    logEntity;    //这就是<any>元素对应的属性。
    
//Getters and Setter 省略
}

2、hbm.xml 和 表结构:
这里只给出MyLog的hbm.xml(BizOne, BizTwo很简单,不提了):

 

< hibernate-mapping >
     
< class  name ="com.test.entity.MyLog"  table ="MyLog" >
        
< id  name ="id"  column ="id" >
            
< generator  class ="native" />
        
</ id >
        
< property  name ="logDate" />
        
< any  name ="logEntity"  meta-type ="string"  id-type ="long" >
              
< meta-value  value ="One"  class ="com.test.entity.BizOne" />
              
< meta-value  value ="Two"  class ="com.test.entity.BizTwo" />
            
< column  name ="entityMetaValue"  length ="20"   />
            
< column  name ="entityId" />
        
</ any >
    
</ class >
</ hibernate-mapping >

表结构(MySQL):

 

create   table  MyLog (
   id 
BIGINT   NOT   NULL  AUTO_INCREMENT,
   logDate 
datetime ,
   entityMetaValue 
VARCHAR ( 20 ),
   entityId 
BIGINT ,
   
primary   key  (id)
)

对<any>元素中子元素和属性的理解,可以结合生成的表结构,及其表中的数据(见3):
name: 是持久类中属性名称。
meta-type: 是下面meta-value元素中value的类型,如"string","character"等。
id-type: 是引用类的主键类型。
meta-value元素中value: 该值将保存到数据库表中,用来标识其后的class,即引用的持久类。请参考下面的数据。
meta-value元素中class: 引用持久类的类全称。
第一个column: 保存上面value值的字段。
第二个column: 保存引用持久类的主键值的字段,它的类型是id-type对应到数据库中的字段类型。

public  MyLog recordLog(Object biz) {
    MyLog log 
= new MyLog();
    log.setLogDate(
new Date());
    log.setLogEntity(biz);    
//引用了传递过来的业务对象

    
return getLogService().save(log);    //保存log。我习惯用Spring+Hibernate。
}

Hibernate所保存的数据是这样:

--  ---------------------------------  ---------------   --------
id  logDate           entityMetaValue entityId
--  ---------------------------------  ---------------   --------
1  2004-11-15 20:48:52.211  One        1
2  2004-11-15 20:57:25.385  Two        2
3  2004-11-15 21:48:52.211  One        15
4  2004-11-15 22:51:15.185  Two        26
5  2004-11-15 23:27:55.123  Two        36

4、读取Log

public  MyLog readLog(Long id) {
    MyLog log 
= getLogService().getLog(id);

    Object biz 
= log.getLogEntity();
    
//...

    
return log;
}
用<any>所实现的关联,与<many-to-one>等关联的效果是相同的。例如,如果BizOne, BizTwo的lazy="true",则biz是个代理。

 

5、BizThree如果增加了一个业务类BizThree,在MyLog.hbm.xml中只需增加一行:

 

代码

6、限制
在<any>元素中需要指定id-type,这可能是<any>对所关联类的唯一限制了:所关联的类的主键类型必须相同。

三、再谈继承映射策略问题
上面提到了:如果为了让Log能够关联业务类,就要求业务类都要继承同一个超类,是不大合适的。不过,不合适的理由在于这个超类需要在数据库有相应的表。不能说,业务类不能继承一个超类。实际上,很多应用中的业务类都有超类,而且根据情况实现一些接口。此时的继承映射策略是Hibernate Reference中的第三种:每个具体类一个表(table per concrete class)。上面MyLog中的logEntity的类型可以是更有意义的超类,如Entity,当然也可以是接口,不必是Object。这样,即使超类在数据库中没有对应的表,照样可以实现关联。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值