2012-03-10 66 views
18

En la clase Parent hay una lista List. Cuando se guarda el elemento primario, los elementos secundarios que se han agregado o modificado se guardarán/actualizarán en hibernación.Hibernar: OneToMany guardar hijos por cascada

He encontrado muchas explicaciones sobre esto, sin embargo, simplemente no consigo que funcione.

Parent.class probar un

@Entity 
public class Parent { 
// id and other attributes 
@OneToMany(mappedBy = "parent") 
@org.hibernate.annotations.Cascade(org.hibernate.annotations.CascadeType.ALL) 
protected List<child> children; 

Parent.class tratar B

@Entity 
public class Parent { 
// id and other attributes 
    @OneToMany(mappedBy = "parent", cascade = { javax.persistence.CascadeType.ALL }, 
orphanRemoval = true) 
@org.hibernate.annotations.Cascade({ 
org.hibernate.annotations.CascadeType.PERSIST, 
org.hibernate.annotations.CascadeType.MERGE, 
org.hibernate.annotations.CascadeType.REFRESH, 
org.hibernate.annotations.CascadeType.SAVE_UPDATE, 
org.hibernate.annotations.CascadeType.REPLICATE, 
org.hibernate.annotations.CascadeType.LOCK, 
org.hibernate.annotations.CascadeType.DETACH }) 
protected List<child> children; 

los niños se añaden a un nuevo padre. Posteriormente ambos son salvados por

sessionFactory.getCurrentSession().saveOrUpdate(parent); 

durante la limpieza, sin embargo, me sale el siguiente error:

org.hibernate.TransientObjectException: object references an unsaved transient instance - save the transient instance before flushing: de.pockettaxi.backend.model.ride.RideSingle 
at org.hibernate.engine.ForeignKeys.getEntityIdentifierIfNotUnsaved(ForeignKeys.java:243) 
at org.hibernate.type.EntityType.getIdentifier(EntityType.java:456) 
at org.hibernate.type.ManyToOneType.isDirty(ManyToOneType.java:265) 
at org.hibernate.type.ManyToOneType.isDirty(ManyToOneType.java:275) 
at org.hibernate.type.TypeHelper.findDirty(TypeHelper.java:295) 
at org.hibernate.persister.entity.AbstractEntityPersister.findDirty(AbstractEntityPersister.java:3378) 
at org.hibernate.event.def.DefaultFlushEntityEventListener.dirtyCheck(DefaultFlushEntityEventListener.java:520) 
at org.hibernate.event.def.DefaultFlushEntityEventListener.isUpdateNecessary(DefaultFlushEntityEventListener.java:230) 
at org.hibernate.event.def.DefaultFlushEntityEventListener.onFlushEntity(DefaultFlushEntityEventListener.java:154) 
at org.hibernate.event.def.AbstractFlushingEventListener.flushEntities(AbstractFlushingEventListener.java:219) 
at org.hibernate.event.def.AbstractFlushingEventListener.flushEverythingToExecutions(AbstractFlushingEventListener.java:99) 
at org.hibernate.event.def.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:50) 
at org.hibernate.impl.SessionImpl.flush(SessionImpl.java:1216) 

¿Alguien ver mi error?

Muchas gracias !!

+2

publique el código para ** niño ** y cómo está construyendo los objetos, befo re the save. – ManuPK

Respuesta

13

supongo que si contesta la pregunta del primer comentario, vamos a llegar a esta situación:

  • que haya una ya persistido padres
  • tiene nuevos objetos secundarios, que aún no se persistió
  • se agregan los hijos a los padres y hacer saveOrUpdate

En ese caso sólo hibernan cascadas guardar o actualización a los niños, pero no se pueden guardar o actualizan en la medida no han sido persistentes todavía. Y ahora Hibernate dice simplemente "No puedo actualizar una entidad no persistente"

En una frase: Hibernate solo conecta en cascada lo que se emite en cascada. En este caso, emite un "SAVE_UPDATE", que se conecta en cascada y luego a los niños. Supongo que esperaba que Hibernate fuera inteligente y cambiara para persistir para los niños aquí. Pero así no es como funciona Hibernate aquí, también me encontré con situaciones similares. Un poco confuso, pero si una vez entendiste cómo funciona la cascada, verás esas situaciones.

5

Necesitaba una forma de insertar una entidad con una nueva entidad unida (hijos) juntas. Una forma de hacerlo es separar las acciones (por ejemplo, guardar primero la entidad unida y luego guardar la entidad principal). Sin embargo, Hibernate admite la inserción de una entidad nueva con una nueva entidad unida. Vea un ejemplo cómo: How to insert OneToMany children by cascade

6

Su Parent.class try A parece correcto. Pero para poner en cascada al niño mientras se guarda el elemento primario, debe colocar la cascada en el lado del propietario (en uno-a-muchos, es la entidad que tiene la clave externa).

probar este

@Entity 
public class Parent { 
    @OneToMany(mappedBy = "parent") 
    protected List<Child> children; 
} 

y en su hijo.clase

@Entity 
public class Child { 
    @ManyToOne 
    @Cascade(value={org.hibernate.annotations.CascadeType.ALL}) 
    @JoinColumn(name="PARENT_ID") 
    protected Parent parent; 
} 
1

Prueba esto:

@Entity 
@Table(name = "TABLE_PARENT") 
public class Parent{ 
    @OneToMany(mappedBy="parent", cascade=CascadeType.PERSIST) 
    private List<Child> children; 
} 

@Entity 
@Table(name = "TABLE_CHILD") 
public class Child{ 
    @ManyToOne(fetch=FetchType.LAZY) 
    @JoinColumn(name="PARENT_ID") 
    private Parent parent; 
} 

Uso

public void save(){ 
    Parent parent = new Parent(); 
    List<Child> children = new ArrayList<>(); 
    Child child = new Child(); 
    child.setParent(parent); 
    children.add(child); 
    parent.setChildren(children); 

    parentRepository.save(parent); 
} 

Nota: No se olvide de establecer la matriz de objeto secundario o se obtendrá TABLE_CHILD.PARENT_ID nula/vacío