6

3 つの Java クラス (Person から Heart、および Person から Liver) のオブジェクト間の単方向の 1 対 1 の関係が必要です。オブジェクトが同じ PK を共有するようにします。つまり、すべての人が対応する心臓と肝臓を持っています。それぞれにたくさんのフィールドがあるため、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 と Heart などの 2 つのクラスを使用したときと同じ動作が得られました)。

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

org.hibernate.id.IdentifierGenerationException: null の 1 対 1 のプロパティから ID を割り当てようとしました: person

ただし、関係を両方の方法で設定すると機能します。

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

しかし、確かにこれは一方向の関係には必要ないのでしょうか?
乾杯

ps。奇妙なことに、Person と Heart などの 2 つのクラスを使用し、リンクを別の方法で設定すると、機能する (両方のオブジェクトが 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のマッピングに no がないことです。

したがって、各 One-To-One にPersonは、Hibernate が公式と見なす参照値​​があります。反対に、他のオブジェクトではmappedBy、値を使用しないで Hibernate に指示しますが、そのオブジェクトに移動し、そのオブジェクトのマップされたプロパティを検討します。


私が正しいかどうかを確認するには、 を持たない値のみを設定しmappedBy、オブジェクトを保存してPerson(カスケードを持つオブジェクトであるため)、結果が正しいかどうかを確認します.. ;-)

于 2009-12-08T15:33:56.710 に答える