unidirectional onetomany one mappedby many example ejemplo spring hibernate jpa parent-child one-to-many

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.