2010-02-03 146 views
6

我在那裏搜索,沒有找到任何相似的主題,所以我發佈了一個新的問題。hibernate複合主鍵包含一個複合外鍵,如何映射這個

我正在Hibernate上使用現有的數據庫。我們不允許更改表格結構和數據。應用程序正在從數據庫中讀取數據,並根據某種邏輯遷移到另一個數據存儲區。

現在的問題是關於複合PK映射。例如

表A具有複合PK。

Table A 
-------- 
a1 (pk) 
a2 (pk) 
a3 (pk) 
a4 (pk) 
foo 
bar 
======== 

表B也有一個複合PK,這個複合PK的一部分是A的PK,這裏也是作爲FK工作的。

Table B 
-------- 
a1 (fk,pk) 
a2 (fk,pk) 
a3 (fk,pk) 
a4 (fk,pk) 
b1 (pk) 
b2 (pk) 
b3 (pk) 
foo 
bar 
======== 

我嘗試了幾種方法,它們都不起作用。任何人都可以告訴一個可用的Hibernate映射解決方案嗎更好的註釋風格。

回答

9

在B的pk Class中將A的實體對象設置爲@ManyToOne。

所以,如果你有

Class A 
Class APK - A's Primary Key 

Class B 
Class BPK - B's primary Key. 

BPK將包含A作爲屬性

@Embeddable 
public class BPK implements serializable { 
    .... 
    private A a; 

    @ManyToOne(fetch=FetchType.EAGER) 
    @JoinColumns ({ 
    @JoinColumn(name="...", referencedColumnName = "..."), 
    @JoinColumn(name="...", referencedColumnName = "..."), 
    ... 
    }) 
    public getA() { 
    return this.a; 
    } 
} 

documentation

@Embeddable繼承 其所屬的實體,除非的接入類型休眠使用3210特定註釋@AccessType爲 。複合外鍵(如果不是 使用默認敏感值) 在使用 @JoinColumns元素(基本上是@JoinColumn數組)的關聯上定義。它 被認爲是一個很好的做法 顯式引用列名稱 。否則,休眠將 假設您使用與 聲明中主鍵 列相同的順序。

+0

@Vinodh Ramasubramania嗨,使用實體作爲主鍵不是一個好主意。 Hibernate Team推薦。您不能在用作主鍵的實體中限制HQL或條件中的查詢結果。因此,有很多方法可以避免使用它。 – 2010-02-03 19:57:55

+0

但我沒有使用實體作爲PK。我使用它(A)與B的PK中的連接條件建立ManyToOne關係。在您的解決方案中,我沒有看到B(BPK)的複合PK是如何用A(APK)的複合PK定義爲它的一個子集。 – 2010-02-03 20:29:37

+0

您的BPK課程中的oneToMany可以幫助我。我沒有想到這個方向。我一直在想如何引用BPK中的另一個APK類。而且不知道如何設置註釋。 爲了方便使用a.getBset(),我使用A類中的joincolumns建模了另一個One2Many。例如私人套裝 bSet ;.在TypeB類中,也是manyToOne,指向TypeA。當然可以插入,updatable = false是需要的。 謝謝你們。 – Kent 2010-02-04 12:44:17

3

如果複合主鍵有只有代理鍵,使用@EmbeddableId

@Embeddable 
public class CompoundIdA implements Serializable { 

    private Integer field0; 
    private Integer field1; 
    private Integer field2; 
    private Integer field3; 

    @Column(name="FIELD_0") 
    public Integer getField0() { 
     return this.field0; 
    } 

    @Column(name="FIELD_1") 
    public Integer getField1() { 
     return this.field1; 
    } 

    @Column(name="FIELD_2") 
    public Integer getField2() { 
     return this.field2; 
    } 

    @Column(name="FIELD_3") 
    public Integer getField3() { 
     return this.field3; 
    } 

    public boolean equals(Object o) { 
     if(o == null) 
      return false; 

     if(!(o instanceof CompoundIdA)) 
      return false; 

     final CompoundIdA other = (CompoundIdA) o; 
     if(!(getField0().equals(other.getField0())) 
      return false; 

     if(!(getField1().equals(other.getField1())) 
      return false; 

     if(!(getField2().equals(other.getField2())) 
      return false; 

     if(!(getField2().equals(other.getField2())) 
      return false; 

     return true; 
    } 

    // hashcode impl 

} 

在ClassA的,我們有

@Entity 
public class ClassA { 

    private CompoundIdA compoundIdA; 

    @EmbeddedId 
    public CompoundIdA getCompoundIdA() { 
     return this.CompoundIdA; 
    } 

} 

如果複合主鍵有自然和代理鍵,再次使用@EmbeddableId

// Let's suppose field0 and field1 are both natural keys 
@Entity 
public class ClassA { 

    private CompoundIdA compoundIdA; 

    private Integer field0; 
    private Integer field1; 

    @EmbeddedId 
    public CompoundIdA getCompoundIdA() { 
     return this.CompoundIdA; 
    } 

    @Column(name="FIELD_0", insertable=false, updateable=false) 
    public Integer getField0() { 
     return this.field0; 
    } 

    @Column(name="FIELD_1", insertable=false, updateable=false) 
    public Integer getField1() { 
     return this.field1; 
    } 

} 

注意您必須設置insertable = false和updateable = false,因爲多個屬性共享同一列。否則,Hibernate會抱怨一些錯誤。

如果複合主鍵有只有自然鍵,如果你要定義一個@ManyToOne使用@IdClass

@Entity 
@IdClass(CompoundIdA.class) 
public class ClassA { 

    private Integer field0; 
    private Integer field1; 
    private Integer field2; 
    private Integer field3; 

    @Id 
    @Column(name="FIELD_0") 
    public Integer getField0() { 
     return this.field0; 
    } 

    @Id 
    @Column(name="FIELD_1") 
    public Integer getField1() { 
     return this.field1; 
    } 

    @Id 
    @Column(name="FIELD_2") 
    public Integer getField2() { 
     return this.field2; 
    } 

    @Id 
    @Column(name="FIELD_3") 
    public Integer getField3() { 
     return this.field3; 
    } 

} 

在ClassB的,你可以使用相同的方法如上圖所示,財產,你必須設置插入=虛假和更新=假如下

@Entity 
public class ClassB { 

    private ClassA classA; 

    @ManyToOne 
    @JoinColumns ({ 
     @JoinColumn(name="FIELD_0", referencedColumnName="FIELD_0", insertable=false, updateable=false), 
     @JoinColumn(name="FIELD_1", referencedColumnName="FIELD_1", insertable=false, updateable=false), 
     @JoinColumn(name="FIELD_2", referencedColumnName="FIELD_2", insertable=false, updateable=false), 
     @JoinColumn(name="FIELD_3", referencedColumnName="FIELD_3", insertable=false, updateable=false) 
    }) 
    public ClassA getClassA() { 
     return this.classA; 
    } 

} 

問候,

+0

我真的沒有看到你的答案和我的很大區別。除了你已經使用了替代註解來描述我已經列出的相同的東西。 – 2010-02-03 19:38:12

+0

我該如何寫同樣的ClassB.hbm.xml? – knocker 2013-01-03 06:37:58