隨筆-9  評(píng)論-168  文章-266  trackbacks-0
          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ù)
          主站蜘蛛池模板: 汤原县| 磐石市| 汤阴县| 无为县| 陇南市| 津市市| 胶南市| 游戏| 黑河市| 平果县| 台北市| 平原县| 陆川县| 榆林市| 万宁市| 定州市| 永和县| 古田县| 苏尼特右旗| 双江| 林芝县| 原平市| 台北市| 加查县| 荥经县| 武宁县| 科技| 迭部县| 德阳市| 隆化县| 淳化县| 奉新县| 大厂| 桐乡市| 彝良县| 乌鲁木齐县| 仁怀市| 张掖市| 中西区| 应用必备| 温州市|