minion
minion

Reputation: 560

Hibernate unable to save child objects using cascade all

I have the following two classes. Class 'Type' has a an object of class 'Content'. I want to save all referenced objects of class 'Type' by using the hibernate.save() method. I have specified the cascade type as ALL in class 'Content'.

Following is the error i face: object references an unsaved transient instance - save the transient instance before flushing.

Can someone please help me identify what the problem is?

public class Type {
    @OneToOne
    @JoinColumn(name = "content_id")
    private Content content;
    }

    public class Content {
        @OneToOne(mappedBy = "content", cascade = CascadeType.ALL)
        private Type type;
    }

    public class Test {
        public void createType() {
            Type type = new Type();
            Content content = someMethodToGetContent();
            type.setContent(content);
            save(type); 
        }

        public void save(Object domainObj) {
            getEntityManager().persist(domainObj);
            getEntityManager().flush();
        }
    }

Stacktrace:

Caused by: org.hibernate.TransientObjectException: object references an unsaved transient instance - save the transient instance before flushing: .content -> .Content at org.hibernate.engine.CascadingAction$9.noCascade(CascadingAction.java:387) at org.hibernate.engine.Cascade.cascade(Cascade.java:172) at org.hibernate.event.def.AbstractFlushingEventListener.cascadeOnFlush(AbstractFlushingEventListener.java:154) at org.hibernate.event.def.AbstractFlushingEventListener.prepareEntityFlushes(AbstractFlushingEventListener.java:145) at org.hibernate.event.def.AbstractFlushingEventListener.flushEverythingToExecutions(AbstractFlushingEventListener.java:88) at org.hibernate.event.def.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:50) at org.hibernate.impl.SessionImpl.flush(SessionImpl.java:1216) at org.hibernate.ejb.AbstractEntityManagerImpl.flush(AbstractEntityManagerImpl.java:795) ... 27 more org.springframework.transaction.TransactionSystemException: Could not commit JPA transaction; nested exception is javax.persistence.RollbackException: Transacti on marked as rollbackOnly at org.springframework.orm.jpa.JpaTransactionManager.doCommit(JpaTransactionManager.java:526) at org.springframework.transaction.support.AbstractPlatformTransactionManager.processCommit(AbstractPlatformTransactionManager.java:761) at org.springframework.transaction.support.AbstractPlatformTransactionManager.commit(AbstractPlatformTransactionManager.java:730) at org.springframework.transaction.interceptor.TransactionAspectSupport.commitTransactionAfterReturning(TransactionAspectSupport.java:504) at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:292) at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:96) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:213) at com.sun.proxy.$Proxy29.persist(Unknown Source) Caused by: javax.persistence.RollbackException: Transaction marked as rollbackOnly at org.hibernate.ejb.TransactionImpl.commit(TransactionImpl.java:73) at org.springframework.orm.jpa.JpaTransactionManager.doCommit(JpaTransactionManager.java:517) ... 12 more

Upvotes: 0

Views: 4351

Answers (2)

ujulu
ujulu

Reputation: 3309

Hibernate unable to save child objects using cascade all

The reason why this does not work has to do with the way you're trying to persit the entities.

  • Let us see what the following code is doing:

    Type type = new Type();
    Content content = someMethodToGetContent();
    type.setContent(content);
    save(type); 
    

You are telling the persistence provider you want to save type by calling save(type) and expecting content should also be saved to the database. But in the entity Type the OneToOne annotation is does not contain the PERSIST cascade option. So you have to tell the persistence provider to to pesist an instance of Content when an instance of Type is persisted by changing your OneToOne annotation as follows:

@OneToOne(cascade=CascadeType.PERSIST)    // modified
@JoinColumn(name = "content_id")
private Content content;

And because you defined to entities to have bi-directional relationship you should wire them as follows correctly:

Type type = new Type();
Content content = someMethodToGetContent();
content.setType(type);                       // modified
type.setContent(content);
save(type); 

Upvotes: 2

Sreenath Reddy
Sreenath Reddy

Reputation: 490

Please change your createType() as below.

public void createType() {
Type type = new Type();
Content content = someMethodToGetContent();
content.setType();
type.setContent(content);
save(type); 
}

Upvotes: 1

Related Questions