WEB开发网
开发学院WEB开发Jsp Hibernate中any元素的应用体会 阅读

Hibernate中any元素的应用体会

 2008-01-05 10:12:19 来源:WEB开发网   
核心提示:Hibernate中any元素的应用体会关联(Associations)是Hibernate核心概念之一,比较常用的有:many-to-one, one-to-one, one-to-many, many-to-manyHibernate还提供了另外一种关联——异类关联(Heterogeneous Associatio

  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、类:
  
  业务类:
  java代码:
  
  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 省略
  }
  
  日志类:
  java代码:
  
  public class MyLog {
  private Long    id;
  private Date    logDate;
  private Object    logEntity;    //这就是<any>元素对应的属性。
  //Getters and Setter 省略
  }
  
  2、hbm.xml 和 表结构:
  
  这里只给出MyLog的hbm.xml(BizOne, BizTwo很简单,不提了):
  
  java代码:
  
  <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):
  java代码:
  
  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对应到数据库中的字段类型。
  
  3、记录日志的方法:
  
  java代码:
  
  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
  java代码:
  
  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中只需增加一行:
  
  java代码:
  
  <meta-value value="Three" class="com.test.entity.BizThree"/>
  
  6、限制
  
  在<any>元素中需要指定id-type,这可能是<any>对所关联类的唯一限制了:所关联的类的主键类型必须相同。
  
  三、再谈继续映射策略问题
  
  上面提到了:假如为了让Log能够关联业务类,就要求业务类都要继续同一个超类,是不大合适的。不过,不合适的理由在于这个超类需要在数据库有相应的表。不能说,业务类不能继续一个超类。实际上,很多应用中的业务类都有超类,而且根据情况实现一些接口。此时的继续映射策略是Hibernate Reference中的第三种:每个具体类一个表(table per concrete class)。上面MyLog中的logEntity的类型可以是更有意义的超类,如Entity,当然也可以是接口,不必是Object。这样,即使超类在数据库中没有对应的表,照样可以实现关联。
  
  四、彩票
  
  Hibernate Reference中提到<any>元素的地方不是很多,但提到时,总不忘记说“应该很少用到”,“应该在非常非凡的情况下使用它”。可能从全世界的角度看,使用<any>是低概率事件,但是假如碰到了,就是100%的概率了。因此,当你应用<any>的时候,别忘了购买彩票。因为,与中奖同样的低概率事件——使用<any>——你已经碰到了,你的运气就来了,赶紧买彩票吧,准能中奖!

Tags:Hibernate any 元素

编辑录入:爽爽 [复制链接] [打 印]
赞助商链接