Frage

Ich mag eine unidirektionale eine Eins-zu-Eins-Beziehung zwischen Objekten von 3 Java-Klassen: Person auf Herz und Person zu Leber. Ich möchte, dass die Objekte die gleiche PK das heißt jede Person teilen hat eine entsprechende Herz und Leber, wo person.person_id = heart.heart_id = liver.liver_id. Ich möchte nicht, die drei Tabellen in 1 verschmelzen, da jede Lasten der Felder hat. Hier ist mein Code (meist auf der Grundlage der akzeptierten Antwort für href="https://stackoverflow.com/questions/787698/jpa-hibernate-one-to-one-relationship">):

@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
}

ich Setup die Sitzung und wie folgt vor:

Person jack = new Person();
jack.setName("jack");
Heart heart = new Heart();
heart.setBpm(80);
Liver liver = new Liver();
liver.setHealthy(true);

Dann, wenn ich die Person Objekt verbinden mit ihm Organe ist, und speichern Sie es, bekomme ich einen Fehler (ANMERKUNG: Ich habe das gleiche Verhalten, wenn ich verwendet nur 2 Klassen zum Beispiel Person und Herz):

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

org.hibernate.id.IdentifierGenerationException: versuchte ID von null zuweisen einer Eins-zu-Eins-Eigenschaft: Person

Allerdings funktioniert es, wenn ich die Beziehung in beiden Richtungen eingestellt:

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

Aber sicher sollte dies nicht notwendig sein, für unidirektionale Beziehungen?
Prost

ps. Merkwürdigerweise merke ich, es funktioniert (speichert beiden Objekte an die DB), wenn ich nur 2 Klassen verwenden, z Person und Herz, und ich einfach auf den Link in die andere Richtung festgelegt:

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

Ich habe keine Ahnung, warum das funktioniert (es mir logisch erscheint, dass Person das Objekt Eltern ist, wie es generiert automatisch eine eigene PK, und die andere verwenden, dass, so alles, was Sie zur Einrichtung haben sollen), aber trotzdem ich kann nicht herausfinden, wie diese Arbeitsweise meiner 3-Klasse Situation anzuwenden ...

War es hilfreich?

Lösung

Ich hasse diese, Ihnen zu sagen, aber Sie haben eine bidirektionale Beziehung gibt. Die Person hat einen Verweis auf das Herz und die Leber und jeder von denen hat einen Verweis zurück auf der Person. Die Anmerkungen, die Sie auf den ID-Eigenschaften Ihres Herzens und Leber eingerichtet sagen ausdrücklich, dass sie durch die Delegation an ihrer Person Eigenschaft den Wert ihrer Id-Eigenschaft erhalten. In den Beispielen, die Sie haben, die nicht funktionieren gezeigt, haben Sie nicht die Person Eigenschaft auf diesen Typen gesetzt noch und so können sie natürlich nicht ihre ID-Wert erhalten.

Sie können entweder diese Beziehung aufgebaut als echter unidirektionale OneToOne, die in der Hibernate Annotations Dokumentation dokumentiert ist:

@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() { ...}
}

oder Sie können unsere Entitätsobjekten beide Seiten der Beziehung zu straffen leicht ändern sich Einhaken wie:

@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
}

Andere Tipps

  

Ich habe es nicht ausprobiert, aber ich würde sagen, dass ....

Ein Unterschied zwischen beiden Seiten ist, dass die Person Klasse hat keine mappedBy in seiner Zuordnung.

Also, für jeden One-To-One, Person hat den Referenzwert, die eine, die Hibernate als offizielle betrachten. Im Gegenteil, auf den anderen Objekten, zeigt die mappedBy Hibernate nicht den Wert zu verwenden, aber auf dieses Objekt gehen und die abgebildete Eigenschaft auf das dem Objekt zu betrachten.


Um zu überprüfen, ob ich Recht habe, könnte man nur die Werte gesetzt, die keine mappedBy haben, und das Person Objekt speichern (weil es derjenige ist, der die Kaskaden hat), und sehen, ob das Ergebnis korrekt ist ..; - )

scroll top