我試圖使用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
和@JoinColumn
在ExtraData
在一起。 我意識到這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;
編輯:
只是爲了澄清,我並不是真的在MainItem
和ExtraData
之間的完全雙向關係之後,但我試圖儘可能地分離兩組數據。
在普通的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
和它帶來任何新成員。
謝謝你的建議,但實際上,我試圖從'MainItem'分開'ExtraData'爲儘可能多。看起來你的建議需要重複從ExtraData到MainItem的所有內容,這正是我想避免的事情之一。 – Bruno
如果你想鏈接'MainItem/ExtraData'只能根據屬性而不是數據(避免字段重複),你可以在'ExtraData'中擁有所有的屬性訪問器,一個到'MainItem'的鏈接(稱爲'mainItem') 'ExtraData.setExtra(string value){this.mainItem.extra = value; }' –
這實際上並不奏效,我只是希望'ExtraData'的一個實例依賴於'MainItem'的一個實例,但我並不想讓'MainItem'有任何與' ExtraData'(理想情況下,'MainItem'甚至不需要引用'ExtraData',但似乎我需要它才能工作,我編輯了我的問題以添加更多細節)。 – Bruno