我正在尝试使用OneToOne
关系将可选数据(ExtraData
)添加到主类(MainItem
)。
ExtraData
的所有实例都应链接到MainItem
的实例,但并非MainItem
的所有实例都需要ExtraData
的实例。
(我主要对单向关系感兴趣,但似乎我需要双向关系才能将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
关系以使关系成为双向关系时,同一个查询在获取MainItem
个实例时不再获取ExtraData
个实例。
以下是添加到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
有什么关系都可以由其他人编码和处理,可能在以后。
是的,如果有人删除main_item
中另一行引用的extra_data
中的行,则extra_data
中的行也将被删除。
使用Hibernate,因为级联没有在生成的外键约束中声明,并且因为它似乎是从另一方的角度声明的,所以我似乎需要双向关系,至少要@OneToOne(mappedBy = "item", cascade = CascadeType.ALL) private ExtraData extraData;
在MainItem
中,以便级联删除(否则删除MainData
实例将失败,因为外键约束在数据库中。)
理想情况下,我希望与ExtraData
相关的代码和数据模型依赖MainItem
中的代码,但原始MainItem
无需了解{{1}无论它带来什么新成员。
答案 0 :(得分: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...
}
}
我希望它可以提供帮助