Pregunta

Quiero un unidireccional uno-a-uno entre los objetos de 3 clases de Java: Persona de corazón, y de persona a hígado. Quiero que los objetos compartan el mismo PK es decir, cada persona tiene un corazón y el hígado correspondiente, donde person.person_id = heart.heart_id = liver.liver_id. No quiero fusionar las tablas 3 a 1 porque cada uno tiene un montón de campos. Aquí está mi código (en su mayoría sobre la base de la respuesta aceptada para esta pregunta ):

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

I fijó la sesión y hacer lo siguiente:

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

Entonces, si puedo enlazar el objeto persona con sus órganos, y lo guarda, me sale un error (NOTA: Tengo el mismo comportamiento cuando acabo de utilizar 2 clases por ejemplo, la persona y del corazón):

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

org.hibernate.id.IdentifierGenerationException: tratado de asignar ID de nula uno-a-una propiedad: persona

Sin embargo funciona si fijo la relación de ambas maneras:

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

Pero sin duda esto no debería ser necesario para las relaciones unidireccionales?
Saludos

ps. Por extraño que parezca, noto que funciona (ahorra ambos objetos a la base de datos) cuando sólo tiene que utilizar, por ejemplo, 2 clases Persona y el corazón, y me acaba de establecer el enlace de la otra manera:

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

No tengo idea de por qué esto funciona (que me parece lógico que la persona es el objeto principal, como se auto-genera su propio PK, y los otros usan eso; así que eso es todo lo que tiene a Setup), pero de todos modos no puedo encontrar la manera de aplicar este método de trabajo a mi situación de clase 3 ...

¿Fue útil?

Solución

No me gusta tener que decirte esto, pero usted tiene una relación bidireccional allí. La persona tiene una referencia al corazón y el hígado y cada uno de los tener una referencia de nuevo a la persona. Las anotaciones que haya configurado en las propiedades ID de su corazón y el hígado están diciendo específicamente que obtienen el valor de su propiedad Id, delegando en sus propiedades persona. En los ejemplos que has demostrado que no funcionan, no se ha establecido la propiedad Persona en esos tipos sin embargo y por lo tanto, es evidente que no puede obtener su valor Id.

Puede establecer esta relación, ya sea como un verdadero unidireccional OneToOne, que se documenta en la documentación de las anotaciones de 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() { ...}
}

o puede cambiar nuestra entidad objetos ligeramente para simplificar conectando ambos lados de la relación, tales como:

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

Otros consejos

  

Yo no lo probamos, pero yo diría que ....

Una diferencia entre ambas partes es que la clase Person no tiene mappedBy en su mapeo.

Por lo tanto, para cada uno Uno A, Person tiene el valor de referencia, la que consideran como Hibernate oficial. Por el contrario, en los otros objetos, la mappedBy indica a Hibernate a no usar el valor, pero ir a ese objeto y considerar la propiedad mapeada en el objeto.


Para comprobar si estoy en lo cierto, podría configurar sólo los valores que no tienen mappedBy, y guardar el objeto Person (ya que es el que tiene las cascadas), y ver si el resultado es correcto ..; - )

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top