2011-09-04 69 views
5

我已經查找了如何在休眠中實現以下關聯的信息,雖然hibernate手冊非常詳盡,但我還沒有找到解決以下用例。如何在java中用hibernate正確實現owner-owned-owner2關聯?

我有一個要求與實體之間的關聯,其中關聯除了關聯實體的外鍵之外還有幾個屬性。關係的規格如下:

  • 容器與通過位置包含關聯。
  • 沒有Container和Contained項目的情況下,職位不能存在。
    • 因此,如果Container或Contained項目被刪除,則應刪除Position。
  • 容器可以包含0個或更多位置。
  • 一個位置是指一個且只有一個包含的項目。

我已經成功地通過註釋配置了大部分需求,除了級聯從Contained項目中刪除外,它工作得非常好。我有一個工作要做到這一點下面描述,但我想通過註釋配置此操作,讓數據庫自動執行工作,以便具有更強大的參照完整性。

這是映射的是我到目前爲止有:

@Entity 
public class Container 
{ 
    @OneToMany(cascade = CascadeType.ALL, 
       orphanRemoval = true, 
       fetch = FetchType.EAGER) 
    @JoinColumn(name = "container_fk") 
    public Set<Position> getPositions() { return this.positions; } 
    public void setPositions(final Set<Position> positions) { this.positions = positions; } 
    private Set<Position> positions; 
    ... 
} 

@Entity 
public class Position 
{ 
    @ManyToOne(fetch = FetchType.EAGER) 
    @JoinColumn(name = "container_fk", insertable = false, updatable = false) 
    @OnDelete(action = OnDeleteAction.CASCADE) 
    public Container getContainer() { return this.container; } 
    public void setContainer(Container container) { this.container = container; } 
    private Container container; 

    @NaturalId 
    @OneToOne(optional = false, fetch = FetchType.EAGER) 
    @JoinColumn(name = "contained_fk") 
    public Contained getContained() { return this.contained; } 
    public void setContained(Contained contained) { this.contained = contained; } 
    private Contained contained; 

    // other attributes are owned by this relationship 
    // (i.e., they don't make sense in either Container or Contained. 
    ... 
} 

要刪除的位置,刪除包含的項目下面是在代碼實現的ContainedDao時(呈現無異常處理和會話管理完成在基DAO類爲簡單起見):

@Repository 
@Transactional(rollbackFor = Throwable.class) 
public class ContainedDao extends TransactionalDao<Contained> 
{ 
    public void delete(String id) 
    { 
     final Session session = getSession(); 

     // If there is a Position associated to the Contained item delete it, 
     // and remove it from any Container collection. 
     Position position = (Position) session.createCriteria(Position.class) 
               .createCriteria("contained") 
               .add(Restrictions.eq("id", id)) 
               .uniqueResult(); 
     if (position != null) 
     { 
      position.getContainer().getPositions().remove(position); 
      session.delete(position); 
     } 

     // Delete the Contained item. 
     Contained object = session.load(Contained.class, id); 
     session.delete(contained); 
    } 
} 

我想要做的就是以某種方式通過註釋配置,以便讓ContainedDao.delete方法被簡化爲一個簡單的:

// Delete the Contained item. 
Contained object = session.load(Contained.class, id); 
session.delete(contained); 

這可能嗎?或者,我現在的解決方案是最好的?有沒有更好的方法來解決這個問題?請注意,這裏的關鍵因素是Position包含附加屬性;否則,我將直接配置Container/Contained之間的關聯並讓hibernate管理關聯。

+0

有沒有什麼辦法可以澄清這個問題,以便評估我是否找到了我所希望的最佳解決方案,或者是否有辦法讓數據庫爲提高參照完整性做好工作? – miguelf

+0

你寫過一個職位只有一個Contained。在其生命週期中,Position實例是否有可能指向兩個或更多個不同的Contained項目? (即你是否打算將外鍵更新爲Contained in Position) –

+0

不,我把它作爲一個不可變屬性。因此,如果您希望指向另一個包含的位置,您將刪除該位置並創建一個新位置。具有position元素的主要原因是由於語義以及因爲它允許在延遲加載包含的對象時獲取這些屬性而保持與關聯相關的屬性。 – miguelf

回答

1

當你說「的位置指的是一個和唯一一個包含的項目」,你的意思是一個一到一個關係(而不是一個多到一個)?如果是這樣的話,那麼我想你真正想表達的是是-al Contained entity。

一個一到一個是-一個關係之間的單差的關係的生命週期。在一對一關係中,位置指向的Contained實例可能會更改。一個is-a關係更受限制:關係本質上是位置本身的身份,因此不允許改變它。

要實現是,一個關係需要三樣東西:

  1. 從position 外鍵載也應位置的主鍵。由於主鍵不變(我允許自己在這裏的豪華推定,你正在使用一個自動生成替代關鍵對Contained)is-a關係也不能更新。當你從Contained中刪除一行時,你必須刪除任何引用的Positions(最多可以有一個)。
  2. Position類應該擴展 Contained類。如上所述的數據庫模型,擴展爲聲明將保留在Position對象的整個生命週期中。當你刪除Contained對象時,你的位置也不見了(它們是內存中的同一個對象,只能通過不同類型的引用訪問)
  3. 在你的Hibernate配置中,指定Position是一個joined-subclass Contained。

然後下面的DAO代碼刪除被包含的情況下也將級聯到您的位置:

public void deleteContained(String id) 
{ 
    Contained c = (Contained) session.createCriteria(Contained.class) 
            .add(Restrictions.eq("id", id)) 
            .uniqueResult(); 

    // Removes associated Position too, if exists 
    session.delete(c); 
    // This would fail now: 
    // session.load(Position.class, id); 
} 

此外,刪除位置實例將級聯包含:

public void deletePosition(String id) 
{ 
    Position p = (Position) session.createCriteria(Position.class) 
            .add(Restrictions.eq("id", id)) 
            .uniqueResult(); 

    // Removes associated Contained too 
    session.delete(p); 
    // This would fail now: 
    // session.load(Contained.class, id); 
} 

附:無論如何,一對一的關係是一個虛假的概念,一個OOP幻覺。此類關係不應使用一對一的方式,而應適當限制爲,或者重新考慮爲多對一的。你可以用上面的多對一替換大部分我的觀點。