Hibernate Annotation幾種關(guān)聯(lián)映射
一對(duì)一(One-To-One)
使用@OneToOne注解建立實(shí)體Bean之間的一對(duì)一關(guān)聯(lián)。一對(duì)一關(guān)聯(lián)有三種情況:(1).關(guān)聯(lián)的實(shí)體都共享同樣的主鍵,(2).其中一個(gè)實(shí)體通過(guò)外鍵關(guān)聯(lián)到另一個(gè)實(shí)體的主鍵(注意要模擬一對(duì)一關(guān)聯(lián)必須在外鍵列上添加唯一約束),(3).通過(guò)關(guān)聯(lián)表來(lái)保存兩個(gè)實(shí)體之間的連接關(guān)系(要模擬一對(duì)一關(guān)聯(lián)必須在每一個(gè)外鍵上添加唯一約束)。
1.共享主鍵的一對(duì)一關(guān)聯(lián)映射:
@Entity
@Table(name="Test_Body")
public class Body {
private Integer id;
private Heart heart;
@Id
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
@OneToOne
@PrimaryKeyJoinColumn
public Heart getHeart() {
return heart;
}
public void setHeart(Heart heart) {
this.heart = heart;
}
}
@Entity
@Table(name="Test_Heart")
public class Heart {
private Integer id;
@Id
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
}
通過(guò)@PrimaryKeyJoinColumn批注定義了一對(duì)一關(guān)聯(lián)
2.使用外鍵進(jìn)行實(shí)體一對(duì)一關(guān)聯(lián):
@Entity
@Table(name="Test_Trousers")
public class Trousers {
@Id
public Integer id;
@OneToOne
@JoinColumn(name = "zip_id")
public TrousersZip zip;
}
@Entity
@Table(name="Test_TrousersZip")
public class TrousersZip {
@Id
public Integer id;
@OneToOne(mappedBy = "zip")
public Trousers trousers;
}
上面的例子是指Trousers通過(guò)Trousers的外鍵列zip_id和TrousersZip關(guān)聯(lián),@JoinColumn批注定義了聯(lián)接列,該批注和@Column批注有點(diǎn)類(lèi)似,但是多了一個(gè)名為referencedColumnName的參數(shù)。該參數(shù)定義了所關(guān)聯(lián)目標(biāo)實(shí)體中的聯(lián)接列,注意,當(dāng)referencedColumnName關(guān)聯(lián)到非主鍵列的時(shí)候,關(guān)聯(lián)的目標(biāo)類(lèi)必須實(shí)現(xiàn)Serializable,還要注意的是所映像的屬性對(duì)應(yīng)單個(gè)列(否則映射無(wú)效)
一對(duì)一關(guān)聯(lián)可能是雙向的,在雙向關(guān)聯(lián)中,有且僅有一端作為主體(owner)端存在:主體端負(fù)責(zé)維護(hù)聯(lián)接列(即更新),對(duì)于不需要維護(hù)這種關(guān)系的從表則通過(guò)mappedNy屬性進(jìn)行聲明。mappedBy的值指向主體的關(guān)聯(lián)屬性。例子中,mappedBy的值為zip。最后,不必也不能再在被關(guān)聯(lián)端(ownedside)定義聯(lián)接列了,因?yàn)橐呀?jīng)在主體端聲明了。
如果在主體沒(méi)有聲明@JoinColumn,系統(tǒng)自動(dòng)進(jìn)行處理:在主表(owner table)中將創(chuàng)建聯(lián)接列,列名為:主體的關(guān)聯(lián)屬性名+下劃線+被關(guān)聯(lián)端的主鍵列名。上面的例子中是zip_id,因?yàn)門(mén)rousers中的關(guān)聯(lián)屬性名為zip,TrousersZip的主鍵是id。
3.通過(guò)關(guān)聯(lián)表定義一對(duì)一關(guān)聯(lián)
@Entity
@Table(name="Test_People")
public class People {
@Id
public Integer id;
@OneToOne
@JoinTable(name ="TestPeoplePassports",
joinColumns =@JoinColumn(name="people_fk"),
inverseJoinColumns =@JoinColumn(name="passport_fk")
)
public Passport passport;
}
@Entity
@Table(name="Test_Passport")
public class Passport {
@Id
public Integer id;
@OneToOne(mappedBy = "passport")
public People people;
}
People通過(guò)名為T(mén)estPeoplePassports的關(guān)聯(lián)表和Passport關(guān)聯(lián)。該關(guān)聯(lián)表?yè)碛忻麨閜assport_fk的外鍵列,該外鍵指向Passport表,該信息定義為inverseJoinColoumns的屬性值,而people_fk外鍵列指向People表,該信息定義為joinColumns的屬性值。
這種關(guān)聯(lián)可能是雙向的,在雙向關(guān)聯(lián)中,有且僅有一端作為主體(owner)端存在:主體端負(fù)責(zé)維護(hù)聯(lián)接列(即更新),對(duì)于不需要維護(hù)這種關(guān)系的從表則通過(guò)mappedNy屬性進(jìn)行聲明。mappedBy的值指向主體的關(guān)聯(lián)屬性。例子中,mappedBy的值為passport。最后,不必也不能再在被關(guān)聯(lián)端(ownedside)定義聯(lián)接列了,因?yàn)橐呀?jīng)在主體端聲明了。
以上是一對(duì)一關(guān)聯(lián)的三種形式,下面介紹多對(duì)一關(guān)聯(lián)。
多對(duì)一(Many-to-One)
使用@ManyToOne批注來(lái)實(shí)現(xiàn)多對(duì)一關(guān)聯(lián)。
@ManyToOne批注有一個(gè)名為targetEntity的參數(shù),該參數(shù)定義了目標(biāo)實(shí)體名,通常不需要定義該參數(shù),因?yàn)樵诖蟛糠智闆r下默認(rèn)值(表示關(guān)聯(lián)關(guān)系的屬性類(lèi)型)就可以很好的滿足需求了。不過(guò)下面這種情況下這個(gè)參數(shù)就顯得有意義了:使用接口作為返回值而不是常見(jiàn)的實(shí)體。
@ManyToOne(targetEntity=CompanyImpl.class)
@JoinColoumn(name=”COPM_ID”)
Public Company getCompany(){
return company;
}
多對(duì)一的配置方式有兩種:(1)通過(guò)@JoinColoumn映像(2)通過(guò)關(guān)聯(lián)表的方式來(lái)映像
(1) 通過(guò)@JoinColoumn映射
SRD Framework中Company,Category例子:
Company:
@ManyToOne
@JoinColumn(name = "CATEGORY_OPTION_ID")
private Category category = null;
Category:
@DiscriminatorValue("Category")
public class Category extends Option {
}
(2) 通過(guò)關(guān)聯(lián)表映射
通過(guò)@JoinTable批注定義關(guān)聯(lián)表,該關(guān)聯(lián)表包含了指回實(shí)體表的外鍵(通過(guò)@JoinTable.joinColoumns)以及指向目標(biāo)實(shí)體表的外鍵(通過(guò)@JoinTable.inverseJoinColoumns)
@Entity
@Table(name="Test_TreeType")
public class TreeType {
private Integer id;
private String name;
private ForestType forestType;
@ManyToOne(fetch = FetchType.LAZY)
@JoinTable(name="Test_Tree_Forest",
joinColumns = @JoinColumn(name="tree_id"),
inverseJoinColumns = @JoinColumn(name="forest_id") )
public ForestType getForestType() {// forestType的getter,setter方法必須在這里,否則會(huì)出錯(cuò)
return forestType;
}
public void setForestType(ForestType forestType) {
this.forestType = forestType;
}
@Id
@GeneratedValue
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
@Entity
@Table(name="Test_ForestType")
public class ForestType {
private Integer id;
private String name;
private Set<TreeType> trees;
@OneToMany(mappedBy="forestType")
public Set<TreeType> getTrees() {// trees的getter,setter方法必須在這里,否則會(huì)出錯(cuò)
return trees;
}
public void setTrees(Set<TreeType> trees) {
this.trees = trees;
}
@Id @GeneratedValue
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
一對(duì)多(One-to-Many)
使用@OneToMany批注可定義一對(duì)多關(guān)聯(lián),一對(duì)多關(guān)聯(lián)可以是雙向關(guān)聯(lián)。
在EJB3規(guī)范中多對(duì)一這端幾乎總是雙向關(guān)聯(lián)中的主體(owner)端,而一對(duì)多這端關(guān)聯(lián)批注為@OneToMany(mappedBy...)
@Entity
Public class Troop{
@OneToMany(mappedBy=”troop”)
Public Set<Soldier> getSoldiers(){
......
}
@Entity
Public class Soldier{
@ManyToOne
@JoinColumn(name=”troop_fk”)
Public Troop getTroop(){
......
}
Troop通過(guò)troop屬性和Soldier建立一對(duì)多的雙向關(guān)聯(lián),在mappedBy端不必也不能再定義任何物理映射。
對(duì)于一對(duì)多的雙向映射,如果要一對(duì)多這一端維護(hù)關(guān)聯(lián)關(guān)系,你需要?jiǎng)h除mappedBy元素并將多對(duì)一這端的@JoinColoumn的insertable和updatabel設(shè)置為false。這種方案不會(huì)得到什么明顯的優(yōu)化,而且還會(huì)增加一些附加的UPDATE語(yǔ)句。
單向:
通過(guò)在被擁有的實(shí)體端(owned entity)增加一個(gè)外鍵列來(lái)實(shí)現(xiàn)一對(duì)多單向關(guān)聯(lián)是很少見(jiàn)的,也是不推薦的,建議通過(guò)一個(gè)聯(lián)接表來(lái)實(shí)現(xiàn)這種關(guān)聯(lián)(下面會(huì)講到)。
@JoinColoumn批注來(lái)描述這種單向關(guān)聯(lián)關(guān)系
@Entity
Public class Customer{
@OneToMany
@JoinColoumn(name=”CUST_ID”)
Public Set<ticket> getTickets() {
......
}
@Entity
Public class Ticket{
...
}
Customer通過(guò)CUST_ID列和Ticket建立了單向關(guān)聯(lián)關(guān)系
通過(guò)關(guān)聯(lián)表處理單向關(guān)聯(lián):
通過(guò)聯(lián)接表處理單向一對(duì)多關(guān)聯(lián)是首選方式,這種關(guān)聯(lián)通過(guò)@JoinTable批注進(jìn)行描述
@Entity
Public class Trainer{
@OneToMany
@JoinTable(
name = "TrainedMonkeys",
jonColumns = {@JoinColumn(name = "trainer_id")},
inverseJoinColumns = @JoinColumn(name = "monkey_id")
)
public Set<Monkey> getTrainedMonkeys() {
return trainedMonkeys;
}
......
}
@Entity
public class Monkey {
...//no bidir
}
上面這個(gè)例子中,Trainer通過(guò)TrainedMonkeys表和Monkey建立了單向關(guān)聯(lián),其中外鍵trainer_id關(guān)聯(lián)到Trainer(joinColoumn),而外鍵monkey_id關(guān)聯(lián)到Monkey(inversejionColoumns)
默認(rèn)處理機(jī)制:
通過(guò)聯(lián)接表來(lái)建立單向一對(duì)多關(guān)聯(lián)不需要描述任何物理映像,表名由以下三個(gè)部分組成:主表(ownertable)表名+從表(the other side table)表名,指向主表的外鍵名:主表表名+下劃線+主表主鍵列名,指向從表的外鍵名:主表所對(duì)應(yīng)實(shí)體的屬性名+下劃線+從表主鍵列名,指向從表的外鍵定義為唯一約束,用來(lái)表示一對(duì)多的關(guān)聯(lián)關(guān)系。
@Entity
public class Trainer{
@OneToMany
Public Set<Tiger> getTrainedTigers(){
... ...
}
@Entity
public class Tiger{
.. ..//no bidir
}
上面這個(gè)例子中,Trainer和Tiger通過(guò)聯(lián)接表Trainer_Tiger建立單向關(guān)聯(lián)關(guān)系,其中外鍵trainer_id關(guān)聯(lián)到Trainer,而外鍵trainedTigers_id關(guān)聯(lián)到Tiger
多對(duì)多(Many-to-Many)
使用@ManyToMany批注可定義多對(duì)多關(guān)聯(lián),同時(shí),你也許要通過(guò)批注@JoinTable描述關(guān)聯(lián)表和關(guān)聯(lián)條件。如果是雙向關(guān)聯(lián),其中一段必須定義為Owner,另一端必須定義為inverse(在對(duì)關(guān)聯(lián)表進(jìn)行更新操作時(shí)這一端將被忽略)
@Entity()
public class Employer implements Serializable {
private Integer id;
private Collection employees;
@ManyToMany(
targetEntity = org.hibernate.test.annotations.manytomany.Employee.class,
cascade = {CascadeType.PERSIST, CascadeType.MERGE}
)
@JoinTable(
name = "EMPLOYER_EMPLOYEE",
joinColumns = {@JoinColumn(name = "EMPER_ID")},
inverseJoinColumns = {@JoinColumn(name = "EMPEE_ID")}
)
public Collection getEmployees() {
return employees;
}
...
}
@Entity()
public class Employee implements Serializable {
@ManyToMany(
cascade = {CascadeType.PERSIST, CascadeType.MERGE},
mappedBy = "employees"
targetEntity = Employer.class
)
public Collection<Employer> getEmployers() {
return employers;
}
.. ..
}
@JoinTable批注定義了聯(lián)接表的表名,聯(lián)接列數(shù)組,以及invers聯(lián)接列數(shù)組,后者是關(guān)聯(lián)表中關(guān)聯(lián)到Employee主鍵的列(the “other side”)。
被關(guān)聯(lián)端不必也不能描述物理映射:只需要一個(gè)簡(jiǎn)單的mappedBy參數(shù),該參數(shù)包含了主體端的屬性名,這樣就綁定了雙方的關(guān)系。
默認(rèn)值:
和其它許多批注一樣,在多對(duì)多關(guān)聯(lián)中很多值是自動(dòng)生成,黨雙向多對(duì)多關(guān)聯(lián)中沒(méi)有定義任何物理映射時(shí),Hibernate根據(jù)以下規(guī)則生成相應(yīng)的值,關(guān)聯(lián)表名:主表表名+下劃線+從表表名,關(guān)聯(lián)到主表的外鍵名:主表名+下劃線+主表中的主鍵列名,關(guān)聯(lián)到從表的外鍵名:主表中用于關(guān)聯(lián)的屬性名+下劃線+從表的主鍵列名,以上規(guī)則對(duì)于雙向一對(duì)多關(guān)聯(lián)同樣一樣。
以上是整理的一點(diǎn)簡(jiǎn)單的幾種映射,可參考EJB3.pdf中P111——P131,hibernate_annotation.pdf 第二章
在這里沒(méi)有具體的例子,有很多內(nèi)容還需要仔細(xì)查看文檔。
posted on 2011-12-20 14:10 紫蝶∏飛揚(yáng)↗ 閱讀(1127) 評(píng)論(0) 編輯 收藏 所屬分類(lèi): Hibernate 、數(shù)據(jù)庫(kù)