java - many - onetoone jpa
JPA @OneToOne con identificación compartida: ¿puedo hacerlo mejor? (2)
Estoy trabajando con un esquema existente que prefiero no cambiar. El esquema tiene una relación uno-a-uno entre las tablas Person y VitalStats, donde Person tiene una clave principal y VitalStats usa el mismo campo que su clave principal y su clave foránea para Person, lo que significa que su valor es el valor de la PK correspondiente. de Persona.
Estos registros son creados por procesos externos, y mi código JPA nunca necesita actualizar VitalStats. Para mi modelo de objeto, me gustaría que mi clase Person contenga un miembro de VitalStats, PERO:
Cuando intento
@Entity
public class Person{
private long id;
@Id
public long getId(){ return id; }
private VitalStats vs;
@OneToOne(mappedBy = “person”)
public VitalStats getVs() { return vs; }
}
@Entity
public class VitalStats{
private Person person;
@OneToOne
public Person getPerson() { return person; }
}
Tengo el problema de que a VitalStats le falta un @Id, que no funciona para un @Entity.
Si intento
@Id @OneToOne
public Person getPerson() { return person; }
eso resuelve el problema @Id pero requiere que la persona sea serializable. Volveremos sobre eso.
Podría hacer VitalStats @Embeddable y conectarlo a Person a través de @ElementCollection, pero luego tendría que accederse como una colección, aunque sé que solo hay un elemento. Doable, pero a la vez un poco molesto y un poco confuso.
Entonces, ¿qué me impide decir que la persona implementa Serializable? Nada, en realidad, excepto que me gusta que todo en mi código esté allí por una razón, y no puedo ver ninguna lógica en esto, lo que hace que mi código sea menos legible.
Mientras tanto, simplemente reemplacé el campo Persona en VitalStats con una ID de persona larga e hice esa Id. De VitalStats, por lo que ahora funciona @OneToOne.
Todas estas soluciones a lo que parece (a mí) como un problema directo son un poco torpes, así que me pregunto si me falta algo, o si alguien al menos puede explicarme por qué Persona tiene que ser serializable.
TIA
En mi caso, esto hizo el truco:
Clase de padres:
public class User implements Serializable {
private static final long serialVersionUID = 1L;
/** auto generated id (primary key) */
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(unique = true, nullable = false)
private Long id;
/** user settings */
@OneToOne(cascade = CascadeType.ALL, mappedBy = "user")
private Setting setting;
}
Clase de niños:
public class Setting implements Serializable {
private static final long serialVersionUID = 1L;
/** setting id = user id */
@Id
@Column(unique = true, nullable = false)
private Long id;
/** user with this associated settings */
@MapsId
@OneToOne
@JoinColumn(name = "id")
private User user;
}
Para correlacionar la asociación uno a uno utilizando claves primarias compartidas, use la anotación @PrimaryKeyJoinColumn
y @MapsId
.
Secciones relevantes de la documentación de referencia de Hibernate:
La anotación PrimaryKeyJoinColumn dice que la clave principal de la entidad se usa como el valor de la clave externa para la entidad asociada.
La anotación de MapsId le pide a Hibernate que copie el identificador de otra entidad asociada. En la jerga de Hibernate, se lo conoce como generador foráneo, pero el mapeo JPA se lee mejor y se recomienda
Person.java
@Entity
public class Person {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "person_id")
private Long id;
@OneToOne(cascade = CascadeType.ALL)
@PrimaryKeyJoinColumn
private VitalStats vitalStats;
}
VitalStats.java
@Entity
public class VitalStats
{
@Id @Column(name="vitalstats_id") Long id;
@MapsId
@OneToOne(mappedBy = "vitalStats")
@JoinColumn(name = "vitalstats_id") //same name as id @Column
private Person person;
private String stats;
}
Tabla de base de
CREATE TABLE person (
person_id bigint(20) NOT NULL auto_increment,
name varchar(255) default NULL,
PRIMARY KEY (`person_id`)
)
Tabla de base de datos VitalStats
CREATE TABLE vitalstats
(
vitalstats_id bigint(20) NOT NULL,
stats varchar(255) default NULL,
PRIMARY KEY (`vitalstats_id`)
)