spring - mappedby - onetomany cascade
JPA @OneToMany-> Parent-Child Reference(clave externa) (5)
¿Realmente tengo que hacer algo? ¿Me gusta esto?
Esa es una estrategia, sí.
En las relaciones bidireccionales, hay un lado "propietario" y otro "no propietario" de la relación. Debido a que el lado propietario en su caso está en el Child
, necesita establecer la relación allí para que persista. El lado propietario generalmente se determina según dónde especifique @JoinColumn
, pero no parece que use esa anotación, por lo que es probable que se mappedBy
del hecho de que utilizó mappedBy
en la anotación Parent
.
Puedes leer mucho más sobre esto aquí .
Tengo una pregunta sobre cómo hacer referencia a ParentEntities desde Child Entites ir Si tengo algo como esto:
Parent.java:
@Entity(name ="Parent")
public class Parent {
@Id
@Generate.....
@Column
private int id;
@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY, mappedBy = "parent")
private Set<Child> children;
simple ... getter and setter ...
}
Y el Niño.java:
@Entity(name ="Child")
public class Child{
@Id
@Generate....
@Column
private int id;
@ManyToOne
private Parent parent;
... simple getter an setter
}
Se crearán las siguientes tablas:
Parent:
int id
Child:
int id
int parent_id (foreign key: parent.id)
Ok, hasta ahora, everths bien. Pero cuando se trata de usar esta referencia desde Java, creo que puedes hacer algo como esto.
@Transactional
public void test() {
Parent parent = new Parent();
Child child = new Child();
Set<Child> children = new HashSet<Child>();
children.add(child);
parent.setChildren(children);
entityManager.persist(parent);
}
lo que lleva a esto en la base de datos:
Parent:
id
100
Child
id paren_id
101 100
Pero ese no es el caso, usted tiene que explicity establecer el Parent to the Child (que, creo, el marco probablemente podría hacer por sí mismo).
Entonces, ¿qué hay realmente en la base de datos es esto?
Parent:
id
100
Child
id paren_id
101 (null)
porque no he configurado Parent to the Child. Entonces mi pregunta:
¿Realmente tengo que hacer algo? ¿Me gusta esto?
Parent.java:
...
setChildren(Set<Child> children) {
for (Child child : children) {
child.setParent.(this);
}
this.children = children;
}
...
Editar:
De acuerdo con las Respuestas rápidas, pude resolver este problema utilizando @JoinColumn en la Entidad propietaria de la referencia. Si tomamos el ejemplo de arriba, hice algo. Me gusta esto:
Parent.java:
@Entity(name ="Parent")
public class Parent {
@Id
@Generate.....
@Column
private int id;
@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
@JoinColumn(name= "paren_id")
private Set<Child> children;
simple ... getter and setter ...
}
Y el Niño.java:
@Entity(name ="Child")
public class Child{
@Id
@Generate....
@Column
private int id;
... simple getter an setter
}
Ahora si hacemos esto:
@Transactional
public void test() {
Parent parent = new Parent();
Child child = new Child();
Set<Child> children = new HashSet<Child>();
children.add(child);
parent.setChildren(children);
entityManager.persist(parent);
}
La referencia está establecida correctamente por el padre:
Parent:
id
100
Child
id paren_id
101 100
Gracias por las respuestas.
Nos encontramos con un problema al persistir un gráfico de objetos simple como el que se muestra arriba. Funcionando en H2, todo funcionaría, pero cuando ejecutamos MySQL, el "paren_id" en la tabla hija (definida en la anotación @JoinColumn) no se llenaba con el ID generado del elemento principal, aunque se configuró como no -columna nula con una restricción de clave externa en el DB.
Obtendremos una excepción como esta:
org.hibernate.exception.GenericJDBCException: Field ''paren_id'' doesn''t have a default value
Para cualquier otra persona que pueda toparse con esto, lo que finalmente encontramos fue que teníamos otro atributo para @JoinColumn
para que funcione:
@JoinColumn(name="paren_id", nullable=false)
Sí, ese es el caso. JPA no se preocupa por la consistencia del gráfico de su entidad. Especialmente tiene que establecerlo en el lado del propietario de la relación bidireccional (en su caso con el atributo principal de Niño).
En la especificación JPA 2.0, esto se dice con las siguientes palabras:
Tenga en cuenta que es la aplicación la que tiene la responsabilidad de mantener la consistencia de las relaciones en tiempo de ejecución, por ejemplo, para asegurar que los lados "uno" y "muchos" de una relación bidireccional sean consistentes entre sí cuando la aplicación se actualice. la relación en tiempo de ejecución.
Si lo EntityManager
correctamente, según EntityManager
, si desea que administre el orden de inserción de la transacción, debe "decirle" que también debe persistir en los niños. Y usted no está haciendo eso, entonces "él" no sabe qué persistir, pero la lista de elementos secundarios de su padre no está vacía, por lo que "él" la toma tiene el valor correcto pero el valor almacenado es nulo.
Entonces deberías considerar hacer algo como:
... begin, etc
em.persist(child)
em.persist(parent)
haz lo que quieras con el objeto principal aquí y luego confirma y esto también debería funcionar para casos similares.
Todavía parece ser el caso. En la Entity
matriz puedes tener algo como
@PrePersist
private void prePersist() {
children.forEach( c -> c.setParent(this));
}
para evitar la repetición de código para establecer una relación niño / padre en otro lugar del código.