Hibernate Annotation幾種關聯映射 數據庫
一對一(One-To-One) 數組
使用@OneToOne註解創建實體Bean之間的一對一關聯。一對一關聯有三種狀況:(1).關聯的實體都共享一樣的主鍵,(2).其中一個實體經過外鍵關聯到另外一個實體的主鍵(注意要模擬一對一關聯必須在外鍵列上添加惟一約束),(3).經過關聯表來保存兩個實體之間的鏈接關係(要模擬一對一關聯必須在每個外鍵上添加惟一約束)。 app
1.共享主鍵的一對一關聯映射: ide
@Entity oop
@Table(name="Test_Body") fetch
public class Body { 優化
private Integer id; this
private Heart heart; spa
@Id hibernate
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;
}
}
經過@PrimaryKeyJoinColumn批註定義了一對一關聯
2.使用外鍵進行實體一對一關聯:
@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經過Trousers的外鍵列zip_id和TrousersZip關聯,@JoinColumn批註定義了聯接列,該批註和@Column批註有點相似,可是多了一個名爲referencedColumnName的參數。該參數定義了所關聯目標實體中的聯接列,注意,當referencedColumnName關聯到非主鍵列的時候,關聯的目標類必須實現Serializable,還要注意的是所映像的屬性對應單個列(不然映射無效)
一對一關聯多是雙向的,在雙向關聯中,有且僅有一端做爲主體(owner)端存在:主體端負責維護聯接列(即更新),對於不須要維護這種關係的從表則經過mappedNy屬性進行聲明。mappedBy的值指向主體的關聯屬性。例子中,mappedBy的值爲zip。最後,沒必要也不能再在被關聯端(ownedside)定義聯接列了,由於已經在主體端聲明瞭。
若是在主體沒有聲明@JoinColumn,系統自動進行處理:在主表(owner table)中將建立聯接列,列名爲:主體的關聯屬性名+下劃線+被關聯端的主鍵列名。上面的例子中是zip_id,由於Trousers中的關聯屬性名爲zip,TrousersZip的主鍵是id。
3.經過關聯表定義一對一關聯
@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經過名爲TestPeoplePassports的關聯表和Passport關聯。該關聯表擁有名爲passport_fk的外鍵列,該外鍵指向Passport表,該信息定義爲inverseJoinColoumns的屬性值,而people_fk外鍵列指向People表,該信息定義爲joinColumns的屬性值。
這種關聯多是雙向的,在雙向關聯中,有且僅有一端做爲主體(owner)端存在:主體端負責維護聯接列(即更新),對於不須要維護這種關係的從表則經過mappedNy屬性進行聲明。mappedBy的值指向主體的關聯屬性。例子中,mappedBy的值爲passport。最後,沒必要也不能再在被關聯端(ownedside)定義聯接列了,由於已經在主體端聲明瞭。
以上是一對一關聯的三種形式,下面介紹多對一關聯。
多對一(Many-to-One)
使用@ManyToOne批註來實現多對一關聯。
@ManyToOne批註有一個名爲targetEntity的參數,該參數定義了目標實體名,一般不須要定義該參數,由於在大部分狀況下默認值(表示關聯關係的屬性類型)就能夠很好的知足需求了。不過下面這種狀況下這個參數就顯得有意義了:使用接口做爲返回值而不是常見的實體。
@ManyToOne(targetEntity=CompanyImpl.class)
@JoinColoumn(name=」COPM_ID」)
Public Company getCompany(){
return company;
}
多對一的配置方式有兩種:(1)經過@JoinColoumn映像(2)經過關聯表的方式來映像
(1)經過@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)經過關聯表映射
經過@JoinTable批註定義關聯表,該關聯表包含了指回實體表的外鍵(經過@JoinTable.joinColoumns)以及指向目標實體表的外鍵(經過@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方法必須在這裏,不然會出錯
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方法必須在這裏,不然會出錯
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;
}
}
一對多(One-to-Many)
使用@OneToMany批註可定義一對多關聯,一對多關聯能夠是雙向關聯。
在EJB3規範中多對一這端幾乎老是雙向關聯中的主體(owner)端,而一對多這端關聯批註爲@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經過troop屬性和Soldier創建一對多的雙向關聯,在mappedBy端沒必要也不能再定義任何物理映射。
對於一對多的雙向映射,若是要一對多這一端維護關聯關係,你須要刪除mappedBy元素並將多對一這端的@JoinColoumn的insertable和updatabel設置爲false。這種方案不會獲得什麼明顯的優化,並且還會增長一些附加的UPDATE語句。
單向:
經過在被擁有的實體端(owned entity)增長一個外鍵列來實現一對多單向關聯是不多見的,也是不推薦的,建議經過一個聯接表來實現這種關聯(下面會講到)。
@JoinColoumn批註來描述這種單向關聯關係
@Entity
Public class Customer{
@OneToMany
@JoinColoumn(name=」CUST_ID」)
Public Set<ticket> getTickets() {
......
}
@Entity
Public class Ticket{
...
}
Customer經過CUST_ID列和Ticket創建了單向關聯關係
經過關聯表處理單向關聯:
經過聯接表處理單向一對多關聯是首選方式,這種關聯經過@JoinTable批註進行描述
@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
}
上面這個例子中,Trainer經過TrainedMonkeys表和Monkey創建了單向關聯,其中外鍵trainer_id關聯到Trainer(joinColoumn),而外鍵monkey_id關聯到Monkey(inversejionColoumns)
默認處理機制:
經過聯接表來創建單向一對多關聯不須要描述任何物理映像,表名由如下三個部分組成:主表(ownertable)表名+從表(the other side table)表名,指向主表的外鍵名:主表表名+下劃線+主表主鍵列名,指向從表的外鍵名:主表所對應實體的屬性名+下劃線+從表主鍵列名,指向從表的外鍵定義爲惟一約束,用來表示一對多的關聯關係。
@Entity
public class Trainer{
@OneToMany
Public Set<Tiger> getTrainedTigers(){
... ...
}
@Entity
public class Tiger{
.. ..//no bidir
}
上面這個例子中,Trainer和Tiger經過聯接表Trainer_Tiger創建單向關聯關係,其中外鍵trainer_id關聯到Trainer,而外鍵trainedTigers_id關聯到Tiger
多對多(Many-to-Many)
使用@ManyToMany批註可定義多對多關聯,同時,你也許要經過批註@JoinTable描述關聯表和關聯條件。若是是雙向關聯,其中一段必須定義爲Owner,另外一端必須定義爲inverse(在對關聯表進行更新操做時這一端將被忽略)
@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批註定義了聯接表的表名,聯接列數組,以及invers聯接列數組,後者是關聯表中關聯到Employee主鍵的列(the 「other side」)。
被關聯端沒必要也不能描述物理映射:只須要一個簡單的mappedBy參數,該參數包含了主體端的屬性名,這樣就綁定了雙方的關係。
默認值:
和其它許多批註同樣,在多對多關聯中不少值是自動生成,黨雙向多對多關聯中沒有定義任何物理映射時,Hibernate根據如下規則生成相應的值,關聯表名:主表表名+下劃線+從表表名,關聯到主表的外鍵名:主表名+下劃線+主表中的主鍵列名,關聯到從表的外鍵名:主表中用於關聯的屬性名+下劃線+從表的主鍵列名,以上規則對於雙向一對多關聯一樣同樣。