神奇好望角 The Magical Cape of Good Hope

          庸人不必自擾,智者何需千慮?
          posts - 26, comments - 50, trackbacks - 0, articles - 11
            BlogJava :: 首頁 ::  :: 聯(lián)系 :: 聚合  :: 管理

          實體間的多對多的關(guān)聯(lián)需要一張關(guān)聯(lián)表。如果直接使用 ManyToMany 來映射,JPA 就會隱式地幫我們自動管理關(guān)聯(lián)表,代碼寫出來和其他類型的關(guān)聯(lián)差別不大。例如,某州炒房團需要一個炒房跟蹤系統(tǒng),那么該系統(tǒng)中的炒房客和房子就是多對多的關(guān)系:

                  public class Speculator implements Serializable {
                      @Id
                      private Integer id;
                      @ManyToMany
                      @JoinTable(joinColumns = @JoinColumn(name = "speculator_id"),
                              inverseJoinColumns = @JoinColumn(name = "house_id"))
                      private List<House> houses;
                      // 此處省略若干行
                  }
          
                  public class House implements Serializable {
                      @Id
                      private Integer id;
                      @ManyToMany(mappedBy = "houses")
                      private List<Speculator> speculators;
                      // 此處省略若干行
                  }
              

          如果炒房客 s 要賣掉房子 h(嚴(yán)格點說是賣掉房子的產(chǎn)權(quán)部分),那么系統(tǒng)執(zhí)行的代碼差不多就是 s.getHouses().remove(h)。看似簡單,然而底層的操作卻性能低下:JPA 會先從數(shù)據(jù)庫中取出炒房客的所有房產(chǎn)(s.getHouses()),然后再刪除指定的那套房子;從數(shù)據(jù)庫層面上看,這將先從關(guān)聯(lián)表(speculator_house)中找到該炒房客的所有房子的外鍵,然后從 house 表載入這些 House 對象,最后才從 speculator_house 刪除關(guān)聯(lián)。在 ORM 出現(xiàn)前,這種操作只需要改關(guān)聯(lián)表,根本不用關(guān)心其他房子。這種簡單的多對多映射寫法將關(guān)聯(lián)表隱藏起來,雖然簡化了代碼,卻也可能帶來性能隱患。

          很自然地可以想到,如果把關(guān)聯(lián)表也映射成實體類,就能解決這個問題。speculator_house 包含兩個外鍵,可用作聯(lián)合主鍵。如果把它映射為 SpeculatorHouse 類,則該類與 SpeculatorHouse 都是多對一的關(guān)系。關(guān)聯(lián)表實體類的代碼如下(EmbeddedId 的映射技巧見《JPA 應(yīng)用技巧 2:主鍵外鍵合體映射》):

                  @Embeddable
                  public class SpeculatorHouseId implements Serializable {
                      private Integer speculatorId;
                      private Integer houseId;
                      // 此處省略若干行
                  }
          
                  @Entity
                  @Table(name = "speculator_house")
                  public class SpeculatorHouse implements Serializable {
                      @EmbeddedId
                      private SpeculatorHouseId id;
                      @MapsId("speculatorId")
                      @ManyToOne
                      private Speculator speculator;
                      @MapsId("houseId")
                      @ManyToOne
                      private House house;
                      // 此處省略若干行
                  }
              

          SpeculatorHouse 也要增加相應(yīng)的關(guān)聯(lián)信息:

                  public class Speculator implements Serializable {
                      @Id
                      private Integer id;
                      @ManyToMany
                      @JoinTable(joinColumns = @JoinColumn(name = "speculator_id"),
                              inverseJoinColumns = @JoinColumn(name = "house_id"))
                      private List<House> houses;
                      @OneToMany(mappedBy = "speculator")
                      private List<SpeculatorHouse> speculatorHouses;
                      // 此處省略若干行
                  }
          
                  public class House implements Serializable {
                      @Id
                      private Integer id;
                      @ManyToMany(mappedBy = "houses")
                      private List<Speculator> speculators;
                      @OneToMany(mappedBy = "house")
                      private List<SpeculatorHouse> speculatorHouses;
                      // 此處省略若干行
                  }
              

          這樣既保留了多對多關(guān)系,又映射了關(guān)聯(lián)表,然后就可以根據(jù)實際情況選擇隱式或顯示的關(guān)聯(lián)表管理。例如,要得到一個炒房客的全部房子,就使用隱式管理:s.getHouses();而要刪除炒房客和某套房子的關(guān)聯(lián),則用顯示管理:delete from SpeculatorHouse sh where sh.speculator = :s and sh.house = :h。


          評論

          # re: JPA 應(yīng)用技巧 3:映射多對多的關(guān)聯(lián)表[未登錄]  回復(fù)  更多評論   

          2012-06-14 16:05 by DD
          但是,我按照你這樣配起來,怎么刪speculator?。。我現(xiàn)在無法刪除speculator。

          # re: JPA 應(yīng)用技巧 3:映射多對多的關(guān)聯(lián)表  回復(fù)  更多評論   

          2012-10-11 15:06 by merge
          對于中間表操作描述詳細,收藏了!
          主站蜘蛛池模板: 贡山| 石嘴山市| 高密市| 那曲县| 洮南市| 长顺县| 元江| 罗平县| 洱源县| 兴业县| 普定县| 安康市| 孝昌县| 兴海县| 嘉黎县| 东平县| 石家庄市| 镇沅| 冕宁县| 浙江省| 小金县| 余姚市| 远安县| 北川| 鸡泽县| 南乐县| 洛扎县| 繁峙县| 高淳县| 旬邑县| 海原县| 灵寿县| 静海县| 鱼台县| 黎川县| 洪雅县| 正安县| 江陵县| 馆陶县| 海丰县| 新乡市|