2010-07-08 10 views
7

Ich habe eine grundlegende Beziehung Beziehung zwischen Eltern/Kind, wie in Kapitel 21 der Hibernate Referenzen Buch.
Die Kaskade ist nur vom Kind zum Eltern (behalte Kaskade nur, weil ich das Eltern nicht löschen möchte, wenn ich ein Kind lösche).
Wenn ich ein Kind zum Vater hinzufügen und ich das Kind zu retten, habe ich eine TransientObjectException ...Hibernate - One-to-viele Beziehung und WaisenkindRemoval Kaskade

@Entity 
public class Parent implements Serializable { 

    @Id 
    @GeneratedValue(strategy = GenerationType.AUTO) 
    private Long id; 

    @OneToMany(mappedBy = "parent", orphanRemoval = true) 
    private List<Child> childs; 

    public List<Child> getChilds() { 
    return childs; 
    } 

    public void setChilds(List<Child> childs) { 
    this.childs = childs; 
    } 

    public void addChild(Child child) { 
    if (childs == null) childs = new ArrayList<Child>(); 
    if (childs.add(child)) child.setParent(this); 
    } 

    public Long getId() { 
    return id; 
    } 

    public void setId(Long id) { 
    this.id = id; 
    } 
} 

@Entity 
public class Child implements Serializable { 

    @Id 
    @GeneratedValue(strategy = GenerationType.AUTO) 
    private Long id; 

    @ManyToOne(optional = false) 
    @Cascade({ PERSIST, MERGE, REFRESH, SAVE_UPDATE, REPLICATE, LOCK, DETACH }) 
    private Parent parent; 

    public Parent getParent() { 
    return parent; 
    } 

    public void setParent(Parent parent) { 
    this.parent = parent; 
    } 

    public Long getId() { 
    return id; 
    } 

    public void setId(Long id) { 
    this.id = id; 
    } 
} 


@Test 
public void test() { 
    Parent parent = new Parent(); 
    Child child = new Child(); 
    parent.addChild(child); 
    genericDao.saveOrUpdate(child); 
} 

Aber auf der saveOrUpdate, habe ich diese Ausnahme:

org.hibernate.TransientObjectException: object references an unsaved transient instance - save the transient instance before flushing: Child 
    at org.hibernate.engine.ForeignKeys.getEntityIdentifierIfNotUnsaved(ForeignKeys.java:244) 
    at org.hibernate.collection.AbstractPersistentCollection.getOrphans(AbstractPersistentCollection.java:911) 
    at org.hibernate.collection.PersistentBag.getOrphans(PersistentBag.java:143) 
    at org.hibernate.engine.CollectionEntry.getOrphans(CollectionEntry.java:373) 
    at org.hibernate.engine.Cascade.deleteOrphans(Cascade.java:471) 
    at org.hibernate.engine.Cascade.cascadeCollectionElements(Cascade.java:455) 
    at org.hibernate.engine.Cascade.cascadeCollection(Cascade.java:362) 
    at org.hibernate.engine.Cascade.cascadeAssociation(Cascade.java:338) 
    at org.hibernate.engine.Cascade.cascadeProperty(Cascade.java:204) 
    at org.hibernate.engine.Cascade.cascade(Cascade.java:161) 
    at org.hibernate.event.def.AbstractSaveEventListener.cascadeAfterSave(AbstractSaveEventListener.java:476) 
    at org.hibernate.event.def.AbstractSaveEventListener.performSaveOrReplicate(AbstractSaveEventListener.java:354) 
    at org.hibernate.event.def.AbstractSaveEventListener.performSave(AbstractSaveEventListener.java:204) 
    at org.hibernate.event.def.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:130) 
    at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.saveWithGeneratedOrRequestedId(DefaultSaveOrUpdateEventListener.java:210) 
    at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.entityIsTransient(DefaultSaveOrUpdateEventListener.java:195) 
    at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.performSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:117) 
    at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.onSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:93) 
    at org.hibernate.impl.SessionImpl.fireSaveOrUpdate(SessionImpl.java:677) 
    at org.hibernate.impl.SessionImpl.saveOrUpdate(SessionImpl.java:669) 
    at org.hibernate.engine.CascadingAction$5.cascade(CascadingAction.java:252) 
    at org.hibernate.engine.Cascade.cascadeToOne(Cascade.java:392) 
    at org.hibernate.engine.Cascade.cascadeAssociation(Cascade.java:335) 
    at org.hibernate.engine.Cascade.cascadeProperty(Cascade.java:204) 
    at org.hibernate.engine.Cascade.cascade(Cascade.java:161) 
    at org.hibernate.event.def.AbstractSaveEventListener.cascadeBeforeSave(AbstractSaveEventListener.java:451) 
    at org.hibernate.event.def.AbstractSaveEventListener.performSaveOrReplicate(AbstractSaveEventListener.java:288) 
    at org.hibernate.event.def.AbstractSaveEventListener.performSave(AbstractSaveEventListener.java:204) 
    at org.hibernate.event.def.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:130) 
    at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.saveWithGeneratedOrRequestedId(DefaultSaveOrUpdateEventListener.java:210) 
    at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.entityIsTransient(DefaultSaveOrUpdateEventListener.java:195) 
    at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.performSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:117) 
    at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.onSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:93) 
    at org.hibernate.impl.SessionImpl.fireSaveOrUpdate(SessionImpl.java:677) 
    at org.hibernate.impl.SessionImpl.saveOrUpdate(SessionImpl.java:669) 
    at org.hibernate.impl.SessionImpl.saveOrUpdate(SessionImpl.java:665) 

ich wirklich don Verstehe nicht, denn das Kind zu retten sollte den Elternteil über die Kaskade retten ... Irgendwelche Ideen?

UPDATE 1
Das Problem scheint da zu "orphanRemoval" verwandt zu sein, wenn ich einen Kommentar auf der parent:

@OneToMany(mappedBy = "parent" /*, orphanRemoval = true */) 
private List<Child> childs; 

Es funktioniert!
Speichern Sie das Kind, dann die Eltern.
Aber ich brauche wirklich die Waise über die Kaskade gelöscht werden, wenn ich ein Kind von seinem Elternteil entfernen.

UPDATE 2
ich eine JIRA Ausgabe erstellt haben:
http://opensource.atlassian.com/projects/hibernate/browse/HHH-5364

UPDATE 3
Es fixiert zu sein scheint :-)
http://opensource.atlassian.com/projects/hibernate/browse/HHH-2269

+0

Willkommen bei Stack-Überlauf! Verwenden Sie die Schaltfläche mit Nullen und Einsen, um Ihren Code in Zukunft korrekt zu formatieren (ich habe ihn für Sie formatiert). –

+0

Danke ... wir haben es gleichzeitig gemacht ;-) –

+0

Was passiert, wenn Sie den Elternteil speichern, bevor Sie das Kind speichern? – Kendrick

Antwort

0

Grundsätzlich Sie verletzen eine Einschränkung. Die Zeile in der db, die dem übergeordneten Element entspricht, ist nicht vorhanden. Daher gibt es keine Fremdschlüsselbeziehung, die das untergeordnete Element verwenden kann, um auf das übergeordnete Element zu verweisen. Fügen Sie einen Aufruf von saveOrUpdate für das übergeordnete Element hinzu, bevor Sie für das untergeordnete Element tun.

(bearbeiten) Ich habe Ihren Kommentar über Kaskade vor der Neuformatierung vermisst. Meine Erinnerung ist, dass die Kaskade nicht auf diese Weise funktioniert; Sie müssten immer noch zuerst die Eltern speichern.

+0

OK, aber das saveOrUpdate wird in einer einzigen Transaktion ausgeführt, so dass zuerst das Kind gespeichert wird, dann sollte die Kaskade das Elternelement erstellen (und den Kind-Fremdschlüssel aktualisieren) und schließlich mit der DB leeren und nur in diesem Moment werden die Einschränkungen validiert. . Nein ? –

+0

haben Sie versucht, 'inverse = true' zum übergeordneten Mapping hinzuzufügen? Ich würde nicht denken, dass das funktionieren würde, aber Hibernate überrascht mich. – Mikeb

+0

Ich verwende keine XML-Konfiguration, sondern Anmerkungen. @ OneToMany (mappedBy = "Eltern") macht das gleiche. –

Verwandte Themen