2013-08-17 85 views
2

我試圖使用OneToOne關係將可選數據(ExtraData)添加到主類(MainItem)。 ExtraData的所有實例都應鏈接到MainItem的實例,但並非所有MainItem實例都需要具有ExtraData的實例。休眠4.2,雙向@OneToOne和@Id

(我在一個單向的關係主要有興趣,但似乎我需要一個雙向的關係,能夠的MainItem的更新和刪除級聯到ExtraData

我使用@Id有麻煩,@OneToOne@JoinColumn連同雙向關係。

的類如下(單向):

@Entity 
@Table(name = "main_item") 
public class MainItem implements Serializable { 
    @Id 
    @Column(name = "id") 
    private int id; 

    @Column(name = "name") 
    private String name; 

    // + getters, setters, toString, ... 
} 

@Entity 
@Table(name = "extra_data") 
public class ExtraData implements Serializable { 
    private static final long serialVersionUID = 1L; 

    @Id 
    @OneToOne 
    @JoinColumn(name = "item_id") 
    private MainItem item; 

    @Column(name = "extra") 
    private String extra; 

    // + getters, setters, toString, ... 
} 

我使用hbm2ddl.auto=update,但我也插了以下數據直接:

INSERT INTO main_item(id, name) VALUES (1, 'Test A'); 
INSERT INTO main_item(id, name) VALUES (2, 'Test B'); 

INSERT INTO extra_data(item_id, extra) VALUES (1, 'Extra A'); 

通過這種單向的關係,得到額外的數據和他們的主要項目工作正常:

Collection<ExtraData> extras = session.createCriteria(ExtraData.class) 
     .list(); 
for (ExtraData extra : extras) { 
    System.out.println(String.format("%s: %s", extra.getItem(), extra)); 
} 

這是輸出:

Hibernate: select this_.item_id as item2_0_0_, this_.extra as extra1_0_0_ from extra_data this_ 
Hibernate: select mainitem0_.id as id1_1_0_, mainitem0_.name as name2_1_0_ from main_item mainitem0_ where mainitem0_.id=? 
Test A: Extra A 

當我加入其他@OneToOne關係,使關係雙向的,同樣的查詢不再得到ExtraData情況下,當得到MainItem實例。

這裏是添加到MainItem代碼(+的get/set):

@OneToOne(mappedBy = "item", cascade = CascadeType.ALL) 
private ExtraData extraData; 

現在,上面的代碼的輸出是:

Hibernate: select this_.item_id as item2_0_0_, this_.extra as extra1_0_0_ from extra_data this_ 
null: Extra A 

我真的不明白爲什麼加入這另一個反轉關係阻止MainItem實例被檢索。 看來這一切都與使用@Id,@OneToOne@JoinColumnExtraData在一起。 我意識到這was not possible with older version,但我使用Hibernate 4.2,它應該支持這一點(雖然我不確定是否有特定的配置設置來激活,但)。

使用同一列到到會員使得它的工作,但我不知道這會不會導致其他衝突:

@Id 
@Column(name = "item_id") 
private int itemId; 

@OneToOne 
@JoinColumn(name = "item_id") 
private MainItem item; 

我還沒得到了一個變型,而無需使用單獨的@Id@OneToOne成員,但以下變體似乎工作(至少對於該測試查詢)。 用Hibernate 4.2做這件事的正確方法是什麼?

  • 使用@PrimaryKeyJoinColumn

    @Id 
    @Column(name = "item_id") 
    private int itemId; 
    
    @OneToOne 
    @PrimaryKeyJoinColumn 
    private MainItem item; 
    
  • 使用@MapsId

    @Id 
    @Column(name = "item_id") 
    private int itemId; 
    
    @OneToOne 
    @MapsId 
    private MainItem item; 
    

編輯:

只是爲了澄清,我並不是真的在MainItemExtraData之間的完全雙向關係之後,但我試圖儘可能地分離兩組數據。

在普通的SQL,我會做這樣的事:

CREATE TABLE main_item (
    id INTEGER PRIMARY KEY, 
    name TEXT 
); 
CREATE TABLE extra_data (
    item_id INTEGER PRIMARY KEY 
     REFERENCES main_item(id) ON UPDATE CASCADE ON DELETE CASCADE, 
    extra TEXT 
); 

這裏,main_item的關注不必知道extra_data什麼。不管怎麼處理extra_data都可以由其他人進行編碼和處理,可能在以後。

是的,如果有人刪除extra_data中另一行引用的main_item中的一行,extra_data中的行也會被刪除。

有了Hibernate,因爲級聯沒有在生成的外鍵約束中聲明,而且因爲它似乎是從另一面的角度聲明的,所以似乎我需要雙向關係,至少在MainItem@OneToOne(mappedBy = "item", cascade = CascadeType.ALL) private ExtraData extraData;,以便刪除級聯(否則刪除MainData實例將失敗,因爲外鍵約束位於數據庫中)。

理想情況下,我想涉及到ExtraData依賴於代碼MainItem的代碼和數據模型,但是原來MainItem不要有了解ExtraData和它帶來任何新成員。

回答

1

是否可選@SecondaryTable@Table一個選項?

@Entity 
@Table(name="MAIN_DATA") 
@SecondaryTable(name="EXTRA_DATA") 
[@org.hibernate.annotations.Table(
    appliesTo="EXTRA_DATA", 
    fetch=FetchMode.SELECT, 
    optional=true) 

的,你可以在MainItem

class MainItem { 
    @Column(name="extra", table="EXTRA_DATA") 
    private String extra; 
    // ...and others field 

    public void setExtraData(ExtraData extra) { 
    this.extra = extra.getExtra(); 
    // etc... 
    } 

    public ExtraData getExtraData() { 
    ExtraData extraData = new ExtraData(); 

    extraData.setExtra(this.extra); 
    // etc... 
    } 
} 

我希望它能夠幫助

+0

謝謝你的建議,但實際上,我試圖從'MainItem'分開'ExtraData'爲儘可能多。看起來你的建議需要重複從ExtraData到MainItem的所有內容,這正是我想避免的事情之一。 – Bruno

+0

如果你想鏈接'MainItem/ExtraData'只能根據屬性而不是數據(避免字段重複),你可以在'ExtraData'中擁有所有的屬性訪問器,一個到'MainItem'的鏈接(稱爲'mainItem') 'ExtraData.setExtra(string value){this.mainItem.extra = value; }' –

+0

這實際上並不奏效,我只是希望'ExtraData'的一個實例依賴於'MainItem'的一個實例,但我並不想讓'MainItem'有任何與' ExtraData'(理想情況下,'MainItem'甚至不需要引用'ExtraData',但似乎我需要它才能工作,我編輯了我的問題以添加更多細節)。 – Bruno