6

我想要 3 个 java 类的对象之间的单向一对一关系:Person to Heart 和 Person to Liver。我希望对象共享相同的 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);

然后,如果我将 person 对象与它的器官链接起来并保存它,我会收到一个错误(注意:当我只使用 2 个类时,我得到了相同的行为,例如 Person 和 Heart):

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

org.hibernate.id.IdentifierGenerationException:试图从 null 一对一属性分配 id:person

但是,如果我以两种方式设置关系,它就会起作用:

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

但是对于单向关系,这肯定不是必需的吗?
干杯

附言。奇怪的是,当我只使用 2 个类(例如 Person 和 Heart)时,我注意到它可以工作(将两个对象都保存到 DB),而我只是以另一种方式设置链接:

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

我不知道为什么会这样(在我看来,Person 是父对象是合乎逻辑的,因为它会自动生成它自己的 PK,而其他人使用它;所以这就是你应该设置的全部),但无论如何我不知道了解如何将这种工作方法应用于我的 3 类情况......

4

2 回答 2

7

我不想告诉你这个,但你在那里有一个双向的关系。人有一个对心脏和肝脏的引用,每个人都有一个对人的引用。您在 Heart 和 Liver 的 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
}
于 2009-12-08T20:40:00.893 回答
1

我没试过,但我会说......

双方的不同之处在于Person该类mappedBy在他的映射中没有。

所以,对于每一个一对一,Person都有参考价值,是 Hibernate 认为是官方的。相反,在其他对象上,mappedBy指示 Hibernate 不使用该值,而是转到该对象并考虑该对象上的映射属性。


要检查我是否正确,您可以只设置没有的值mappedBy,然后保存Person对象(因为它是具有级联的对象),然后查看结果是否正确.. ;-)

于 2009-12-08T15:33:56.710 回答