2012-03-10 8 views
18

Nella classe Parent è presente un elenco. Quando il genitore viene salvato, i bambini che sono stati aggiunti o modificati devono essere salvati/aggiornati dallo stato di ibernazione.Hibernate: OneToMany salva i bambini per cascata

Ho trovato molte spiegazioni su questo, tuttavia, non riesco a farlo funzionare.

Parent.class provare 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 provare 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; 

bambini vengono aggiunti a un nuovo genitore. In seguito entrambi sono salvati da

sessionFactory.getCurrentSession().saveOrUpdate(parent); 

quando si lava, però, ottengo il seguente errore:

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) 

Qualcuno vede il mio errore?

Grazie mille !!

+2

pubblicare il codice per ** figlio ** e come si sta costruendo gli oggetti, befo risparmi. – ManuPK

risposta

13

Credo che se si risponde alla domanda del primo commento, noi verremo a questa situazione:

  • avete uno già persistito genitore
  • si dispone di nuovi oggetti figlio, che non sono stati ancora persistenti
  • si aggiungono i figli al genitore e fare saveOrUpdate

In questo caso vanno in letargo solo cascate del salva o si aggiorna ai bambini, ma non può essere salvato o aggiornato come non sono ancora persistenti. E ora Hibernate dice semplicemente "Non posso aggiornare un'entità non persistente"

In una frase: Hibernate esegue solo la cascata di ciò che viene emesso a cascata. In questo caso si emette un "SAVE_UPDATE", che viene poi collegato in cascata ai figli. Immagino che tu ti aspetti che Hibernate sia intelligente e che passi qui per i bambini. Ma non è così che funziona Hibernate, mi sono imbattuto in situazioni simili anche prima. Un po 'di confusione, ma se una volta hai capito come funziona la cascata, vedrai queste situazioni.

5

Avevo bisogno di un modo per inserire un'entità con una nuova entità (figli) unita. Un modo per farlo è separare le azioni (ad es. Per salvare prima l'entità unita e poi salvare l'entità principale). Tuttavia, il supporto di Hibernate inserisce una nuova entità con una nuova entità unita. Vedere un esempio come: How to insert OneToMany children by cascade

6

Il tuo Parent.class prova A sembra già corretto. Ma per mettere in cascata il bambino salvando il genitore, devi mettere la cascata dal lato del proprietario (in uno-a-molti, è l'entità che ha la chiave esterna).

Prova questa

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

e nel vostro bambino.Classe

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

Prova questo:

@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: Non dimenticare di impostare il genitore sull'oggetto figlio o si otterrà TABLE_CHILD.PARENT_ID null/vuoto