Hibernate中any元素的應用體會
關聯(Associations)是Hibernate核心概念之一
比較常用的有
many
to
one
one
to
one
one
to
many
many
to
many
Hibernate還提供了另外一種關聯——異類關聯(Heterogeneous Associations)
在Hibernate Reference (cn)
中是這樣說明的
引用: 異類關聯(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提供的三種繼承映射策略中
只能使用前兩種
每棵類繼承樹使用一個表(table per class hierarchy)
每個子類一個表(table per subclass)
第
種通常不大合適
所有的業務類映射為一張表
冗余過多
限制也多
增加一個業務類就需要修改表結構
不易擴展
第
種的情況是
表的數量=業務表數量 + 一個超類表
子類表通過主鍵和超類表關聯(所以實際上關系模型是一對一關聯)
業務表數量比較多的時候
這種結構的性能和靈活性都有問題
這時<any>元素就派上用場啦
二<any>元素的應用 類
業務類
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 省略
}
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=
/>
<column name=
entityId
/>
</any>
</class>
</hibernate
mapping>
表結構(MySQL)
java代碼:
create table MyLog (
id BIGINT NOT NULL AUTO_INCREMENT
logDate datetime
entityMetaValue VARCHAR(
)
entityId BIGINT
primary key (id)
)
對<any>元素中子元素和屬性的理解
可以結合生成的表結構
及其表中的數據(見
)
name: 是持久類中屬性名稱
meta
type: 是下面meta
value元素中value的類型
如
string
character
等
id
type: 是引用類的主鍵類型
meta
value元素中value: 該值將保存到數據庫表中
用來標識其後的class
即引用的持久類
請參考下面的數據
meta
value元素中class: 引用持久類的類全稱
第一個column: 保存上面value值的字段
第二個column: 保存引用持久類的主鍵值的字段
它的類型是id
type對應到數據庫中的字段類型
記錄日志的方法
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
:
:
One
:
:
Two
:
:
One
:
:
Two
:
:
Two
讀取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是個代理
BizThree如果增加了一個業務類BizThree
在MyLog
hbm
xml中只需增加一行
java代碼:
<meta
value value=
Three
class=
com
test
entity
BizThree
/>
限制
在<any>元素中需要指定id
type
這可能是<any>對所關聯類的唯一限制了
所關聯的類的主鍵類型必須相同
三再談繼承映射策略問題 上面提到了
如果為了讓Log能夠關聯業務類
就要求業務類都要繼承同一個超類
是不大合適的
不過
不合適的理由在於這個超類需要在數據庫有相應的表
不能說
業務類不能繼承一個超類
實際上
很多應用中的業務類都有超類
而且根據情況實現一些接口
此時的繼承映射策略是Hibernate Reference中的第三種
每個具體類一個表(table per concrete class)
上面MyLog中的logEntity的類型可以是更有意義的超類
如Entity
當然也可以是接口
不必是Object
這樣
即使超類在數據庫中沒有對應的表
照樣可以實現關聯
四彩票 Hibernate Reference中提到<any>元素的地方不是很多
但提到時
總不忘記說
應該很少用到
應該在非常特殊的情況下使用它
可能從全世界的角度看
使用<any>是低概率事件
但是如果遇到了
就是
%的概率了
因此
當你應用<any>的時候
別忘了購買彩票
因為
與中獎同樣的低概率事件——使用<any>——你已經碰到了
你的運氣就來了
趕快買彩票吧
准能中獎!
From:http://tw.wingwit.com/Article/program/Java/ky/201311/28015.html