2009-12-08 58 views
5

我想要一個單向 3個java類的對象之間的一對一關係:Person to Heart和Person to Liver。我想讓這些物品共享相同的PK,即每個人都有相應的心臟和肝臟,其中person.person_id = heart.heart_id = liver.liver_id。我不想將3個表合併爲1,因爲每個表都有多個字段。這裏是我的代碼(主要是基於公認的答案爲this question):休眠一對一實體關聯與3個類別之間的共享PK

@Entity 
public class Person { 
    public long personId; 
    private String name; 
    public Heart heart; 
    public Liver liver; 
    // other fields 

    @Id 
    @GeneratedValue 
    public long getPersonId() {return personId;} 

    @OneToOne(cascade = CascadeType.ALL) 
    @PrimaryKeyJoinColumn 
    public Heart getHeart() {return heart;} 

    @OneToOne(cascade = CascadeType.ALL) 
    @PrimaryKeyJoinColumn 
    public Liver getLiver() {return liver;} 

    // other getters and setters and constructors 
} 


@Entity 
public class Heart { 
    private long heartId; 
    private int bpm; 
    private Person person; 
    // other fields 

    @Id 
    @GenericGenerator(
     name = "generator", 
     strategy = "foreign", 
     parameters = @Parameter(name = "property", value = "person") 
    ) 
    @GeneratedValue(generator = "generator") 
    public long getHeartId() {return heardId;} 

    @OneToOne(mappedBy="heart") 
    @PrimaryKeyJoinColumn 
    public Person getPerson() {return person;} 

    // other getters and setters and constructors 
} 


@Entity 
public class Liver { 
    private long liverId; 
    private boolean healthy; 
    private Person person; 
    // other fields 

    // the rest uses the same hibernate annotation as Heart 
} 

我建立會話,並執行以下操作:

Person jack = new Person(); 
jack.setName("jack"); 
Heart heart = new Heart(); 
heart.setBpm(80); 
Liver liver = new Liver(); 
liver.setHealthy(true); 

然後,如果我連接起來,人物對象與它的器官,和保存它,我得到一個錯誤(注:我的時候我只用2類相同的行爲,例如人與心):

jack.setHeart(heart); 
jack.setLiver(liver); 
session.save(jack); 

組織。 hibernate.id.IdentifierGenerationException:試圖從空一到一個屬性分配ID:人

但是它的工作原理,如果我設定的關係是雙向的:

jack.setHeart(heart); 
heart.setPerson(jack); 
jack.setLiver(liver); 
liver.setPerson(jack); 
session.save(jack); 

但可以肯定這不應該是單向關係需要嗎?
乾杯

ps。奇怪的是,我注意到它的工作原理(將兩個對象保存到數據庫),當我只使用2個類時,例如人與心,我只是設置鏈接的其他方式:

heart.setPerson(jack); 
session.save(heart); 

我不知道爲什麼這工作(這似乎是合乎邏輯,我認爲人是父對象,因爲它會自動生成它自己的PK,和其他人使用,所以這就是你應該有設置),但無論如何,我無法弄清楚如何將這種工作方法適用於我的3級的情況...

+0

我剛剛發現這個問題,我認爲這是對於同樣的情況,但使用了完全不同的方法(它使用@Embeddable和@Inheritance):http://stackoverflow.com/questions/ 904634。唯一的問題是,我接受的解決方案中沒有足夠的相關代碼來理解/實施它......任何人都可以提供幫助嗎? – jackocnr 2009-12-08 20:04:49

回答

6

我不想告訴你這一點,但你有一個雙向的關係。該人有一個對心臟和肝臟的參考,並且每個人都有一個參照。您在心臟和肝臟的Id屬性上設置的註釋特別說明,他們通過委派他們的Person屬性來獲得他們Id身份的價值。在你已經顯示不起作用的例子中,你還沒有爲這些人設置Person屬性,所以他們顯然無法獲得他們的Id值。

您可以設置這種關係了作爲一個真正的單向OneToOne,這是Hibernate的註釋文檔中記載:

@Entity 
public class Body { 
    @Id 
    public Long getId() { return id; } 

    @OneToOne(cascade = CascadeType.ALL) 
    @PrimaryKeyJoinColumn 
    public Heart getHeart() { 
     return heart; 
    } 
    ... 
} 


@Entity 
public class Heart { 
    @Id 
    public Long getId() { ...} 
} 

,或者你可以改變我們的實體略有對象,以簡化掛鉤的關係,雙方如:

@Entity 
public class Person { 
    public long personId; 
    private String name; 
    public Heart heart; 
    public Liver liver; 
    // other fields 

    @Id 
    @GeneratedValue 
    public long getPersonId() {return personId;} 

    @OneToOne(cascade = CascadeType.ALL) 
    @PrimaryKeyJoinColumn 
    public Heart getHeart() {return heart;} 

    public void setHeart(Heart heart){ 
     this.heart = heart; 
     this.heart.setPerson(this); 
    } 

    @OneToOne(cascade = CascadeType.ALL) 
    @PrimaryKeyJoinColumn 
    public Liver getLiver() {return liver;} 

    public void setLiver(Liver liver){ 
     this.liver = liver; 
     this.liver.setPerson(this); 
    } 
    // other getters and setters and constructors 
} 
+0

我試過了文檔中的例子,但我不明白它是如何工作的:沒有什麼可以保持3個表格之間的ID一致。在心臟和肝臟類別中有一個人員領域的唯一原因是針對外國@GenericGenerator,因此所有心臟和肝臟對象都將具有與其相應人員對象相同的ID。注意:如果我從Heart和Liver類的getPerson()中刪除@OneToOne和@PrimaryKeyJoinColumn,我會得到與引用問題相同的錯誤。 – jackocnr 2009-12-09 11:36:37

1

我沒有嘗試,但我會說...

雙方的區別在於Person在他的映射中沒有mappedBy

所以,對於每個One-To-One,Person都有參考價值,Hibernate認爲是官方的。相反,在其他對象上,mappedBy指示Hibernate不使用該值,但轉到該對象並考慮該對象上的映射屬性。


要檢查,如果我是正確的,你可以設置只沒有mappedBy值,並保存Person對象(因爲它是具有級聯的一個),看看結果是正確的.. ;-)

+0

我可以創建一個新的Person對象,設置他的名字並保存他,沒有任何錯誤。但是,如果我創建一個新的Heart對象,將它設置爲bpm字段並保存它,我再次得到該IdentifierGenerationException。你是這個意思嗎?你知道解決方法嗎? – jackocnr 2009-12-08 19:16:23