我想要3个Java类的对象之间的 单向 一对一关系:“人到心脏”和“人到肝脏”。我希望对象共享相同的PK,即每个人都有相应的心脏和肝脏,其中person.person_id = heart.heart_id = liver.liver_id。我不想将3个表合并为1个表,因为每个表都有很多字段。这是我的代码(主要基于该问题的公认答案):
@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);
org.hibernate.id.IdentifierGenerationException:尝试从空的一对一属性分配id:person
但是,如果我同时设置两种关系,它会起作用:
jack.setHeart(heart); heart.setPerson(jack); jack.setLiver(liver); liver.setPerson(jack); session.save(jack);
但是,对于单向关系,肯定不需要这样做吗? 干杯
ps。奇怪的是,当我仅使用2类(例如Person和Heart),并且以另一种方式设置链接时,我注意到它起作用(将两个对象都保存到DB中):
heart.setPerson(jack); session.save(heart);
我不知道为什么这行得通(在我看来,Person是父对象,因为它自动生成自己的PK,而其他人使用它;所以这就是您应该设置的全部),但是无论如何我都无法弄清楚了解如何将这种工作方法应用于我的3类情况…
我不愿意告诉您这一点,但是您在那里存在双向关系。该人提及心脏和肝脏,并且每个人都提及该人。您在“心脏”和“肝脏”的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 }