Home Hibernate Fix for "object references an unsaved transient instance - save the transient...

Fix for “object references an unsaved transient instance – save the transient instance beforeQuery flushing” in Hibernate

When I am working with association in JPA with Hibernate, Error during managed flush [org.hibernate.TransientObjectException: object references an unsaved transient instance – save the transient instance beforeQuery flushing …] is one of the common error often I have seen.

Lets’s see when this Error occur and how to fix this issue. First let’s reproduce the issue.

1. Reproducing Issue

Entity Mappings:

@Entity
public class Student implements Serializable {
	
	@Id
	private int id;

	@Column(name="CONTACT_NO")
	private String contactNo;

	private String fname;

	private String lname;

        // ... omitted setters and getters
}
@Entity
public class Branch implements Serializable {
	
	@Id
	@Column(name="BRANCH_ID")
	private int branchId;

	@Column(name="BRANCH_NAME")
	private String branchName;

	@Column(name="BRANCH_SHORT_NAME")
	private String branchShortName;

	private String description;

	//uni-directional one-to-many association to Student
	@OneToMany(orphanRemoval = true)
	@JoinColumn(name="BRANCH_ID")
	private List<Student> students;

	// .. omitted setters getters etc.

}

Let’s save Branch entity.

			Branch branch = new Branch();
			branch.setBranchShortName("CSE");
			branch.setBranchName("Computer Science and Engineering");
			branch.setDescription("CSE department offers courses under ambitious curriculum in computer science ..");
			List<Student> students = new ArrayList<Student>();
			students.add(getStudent1());
			students.add(getStudent2());
			branch.setStudents(students);
			
			entityManager.persist(branch);
			transaction.commit();

Output:

We will get ERROR: HHH000346: Error during managed flush [org.hibernate.TransientObjectException: object references an unsaved transient instance – save the transient instance beforeQuery flushing: com.javabydeveloper.domain.Student]

Hibernate: insert into Branch (BRANCH_NAME, BRANCH_SHORT_NAME, description) values (?, ?, ?)
Hibernate: update Student set BRANCH_ID=? where id=?
Nov 19, 2020 10:55:19 AM org.hibernate.internal.ExceptionMapperStandardImpl mapManagedFlushFailure
ERROR: HHH000346: Error during managed flush [org.hibernate.TransientObjectException: object references an unsaved transient instance - save the transient instance beforeQuery flushing: com.javabydeveloper.domain.Student]
javax.persistence.RollbackException: Error while committing the transaction
	at org.hibernate.internal.ExceptionConverterImpl.convertCommitException(ExceptionConverterImpl.java:75)
	at org.hibernate.engine.transaction.internal.TransactionImpl.commit(TransactionImpl.java:71)
	at com.javabydeveloper.App.main(App.java:43)
Caused by: java.lang.IllegalStateException: org.hibernate.TransientObjectException: object references an unsaved transient instance - save the transient instance beforeQuery flushing: com.javabydeveloper.domain.Student
	at org.hibernate.internal.ExceptionConverterImpl.convert(ExceptionConverterImpl.java:144)
	at org.hibernate.internal.ExceptionConverterImpl.convert(ExceptionConverterImpl.java:155)
	at org.hibernate.internal.ExceptionConverterImpl.convert(ExceptionConverterImpl.java:162)
	at org.hibernate.internal.SessionImpl.doFlush(SessionImpl.java:1434)
	at org.hibernate.internal.SessionImpl.managedFlush(SessionImpl.java:484)
	at org.hibernate.internal.SessionImpl.flushBeforeTransactionCompletion(SessionImpl.java:3190)
	at org.hibernate.internal.SessionImpl.beforeTransactionCompletion(SessionImpl.java:2404)
	at org.hibernate.engine.jdbc.internal.JdbcCoordinatorImpl.beforeTransactionCompletion(JdbcCoordinatorImpl.java:467)
	at org.hibernate.resource.transaction.backend.jdbc.internal.JdbcResourceLocalTransactionCoordinatorImpl.beforeCompletionCallback(JdbcResourceLocalTransactionCoordinatorImpl.java:146)
	at org.hibernate.resource.transaction.backend.jdbc.internal.JdbcResourceLocalTransactionCoordinatorImpl.access$100(JdbcResourceLocalTransactionCoordinatorImpl.java:38)
	at org.hibernate.resource.transaction.backend.jdbc.internal.JdbcResourceLocalTransactionCoordinatorImpl$TransactionDriverControlImpl.commit(JdbcResourceLocalTransactionCoordinatorImpl.java:220)
	at org.hibernate.engine.transaction.internal.TransactionImpl.commit(TransactionImpl.java:68)
	... 1 more
Caused by: org.hibernate.TransientObjectException: object references an unsaved transient instance - save the transient instance beforeQuery flushing: com.javabydeveloper.domain.Student
	at org.hibernate.engine.internal.ForeignKeys.getEntityIdentifierIfNotUnsaved(ForeignKeys.java:279)
	at org.hibernate.type.EntityType.getIdentifier(EntityType.java:462)
	at org.hibernate.type.ManyToOneType.nullSafeSet(ManyToOneType.java:151)
	at org.hibernate.persister.collection.AbstractCollectionPersister.writeElement(AbstractCollectionPersister.java:894)
	at org.hibernate.persister.collection.AbstractCollectionPersister.recreate(AbstractCollectionPersister.java:1317)
	at org.hibernate.persister.collection.OneToManyPersister.recreate(OneToManyPersister.java:186)
	at org.hibernate.action.internal.CollectionRecreateAction.execute(CollectionRecreateAction.java:50)
	at org.hibernate.engine.spi.ActionQueue.executeActions(ActionQueue.java:586)
	at org.hibernate.engine.spi.ActionQueue.executeActions(ActionQueue.java:460)
	at org.hibernate.event.internal.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:337)
	at org.hibernate.event.internal.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:39)
	at org.hibernate.internal.SessionImpl.doFlush(SessionImpl.java:1428)
	... 9 more

2. Understanding Root Cause

one-to-many association

Hibernate first inserted Branch record in database and trying to update foreign key BRANCH_ID in Student table. But Student record not yet inserted in DB. Which means, the Student entity state is transient in Persistence Context.

So, Branch object has reference (Student), which is an unsaved transient instance. We need to save Student (transient instance) before Hibernate flushing Branch.

3. Solution

In Hibernate, In Parent and Child table association mappings, this is a common issue. To fix the issue, we need to apply proper Cascading operation to the reference in Branch entity using CascadeType.

CascadeType propagates entity transitions from Parent to Child. For example, if you persist parent entity the referenced entities also get persisted before flushing. Let’s update the Branch entity using CascadeType.ALL.

@Entity
public class Branch implements Serializable {
	
	@Id
	@Column(name="BRANCH_ID")
	private int branchId;

	@Column(name="BRANCH_NAME")
	private String branchName;

	@Column(name="BRANCH_SHORT_NAME")
	private String branchShortName;

	private String description;

	//uni-directional one-to-many association to Student
	@OneToMany(cascade = CascadeType.ALL , orphanRemoval = true)
	@JoinColumn(name="BRANCH_ID")
	private List<Student> students;

	// .. omitted setters getters etc.

}

Let’s run the program again and verify results.

Hibernate: insert into Branch (BRANCH_NAME, BRANCH_SHORT_NAME, description) values (?, ?, ?)
Hibernate: insert into Student (CONTACT_NO, fname, lname) values (?, ?, ?)
Hibernate: insert into Student (CONTACT_NO, fname, lname) values (?, ?, ?)
Hibernate: update Student set BRANCH_ID=? where id=?
Hibernate: update Student set BRANCH_ID=? where id=?
Nov 19, 2020 11:21:43 AM org.hibernate.engine.jdbc.connections.internal.DriverManagerConnectionProviderImpl stop

Now, we can notice Student records get updated before updating BRANCH_ID foreign key in Student table.

4. Conclusion

We have seen the root cause of issue “object references an unsaved transient instance – save the transient instance beforeQuery flushing” in JPA with Hibernate and how to fix the issue.

Satish Varma
Satish Varmahttps://javabydeveloper.com
Satish is post graduated in master of computer applications and experienced software engineer with focus on Spring, JPA, REST, TDD and web development. Follow him on LinkedIn or Twitter or Facebook

LEAVE A REPLY

Please enter your comment!
Please enter your name here

Stay in Touch

Subscribe

Subscribe for latest updates.

 

Loading

Categories