How to fix the Hibernate "object references an unsaved transient instance - save the transient instance before flushing" error
Solution 1
You should include cascade="all"
(if using xml) or cascade=CascadeType.ALL
(if using annotations) on your collection mapping.
This happens because you have a collection in your entity, and that collection has one or more items which are not present in the database. By specifying the above options you tell hibernate to save them to the database when saving their parent.
Solution 2
I believe this might be just repeat answer, but just to clarify, I got this on a @OneToOne
mapping as well as a @OneToMany
. In both cases, it was the fact that the Child
object I was adding to the Parent
wasn't saved in the database yet. So when I added the Child
to the Parent
, then saved the Parent
, Hibernate would toss the "object references an unsaved transient instance - save the transient instance before flushing"
message when saving the Parent.
Adding in the cascade = {CascadeType.ALL}
on the Parent's
reference to the Child
solved the problem in both cases. This saved the Child
and the Parent
.
Sorry for any repeat answers, just wanted to further clarify for folks.
@OneToOne(cascade = {CascadeType.ALL})
@JoinColumn(name = "performancelog_id")
public PerformanceLog getPerformanceLog() {
return performanceLog;
}
Solution 3
Introduction
When using JPA and Hibernate, an entity can be in one of the following 4 states:
- New - A newly created object that hasn’t ever been associated with a Hibernate Session (a.k.a Persistence Context) and is not mapped to any database table row is considered to be in the New or Transient state.
To become persisted we need to either explicitly call the persist
method or make use of the transitive persistence mechanism.
- Persistent - A persistent entity has been associated with a database table row and it’s being managed by the currently running Persistence Context.
Any change made to such an entity is going to be detected and propagated to the database (during the Session flush-time).
-
Detached - Once the currently running Persistence Context is closed all the previously managed entities become detached. Successive changes will no longer be tracked and no automatic database synchronization is going to happen.
-
Removed - Although JPA demands that managed entities only are allowed to be removed, Hibernate can also delete detached entities (but only through a
remove
method call).
Entity state transitions
To move an entity from one state to the other, you can use the persist
, remove
or merge
methods.
Fixing the problem
The issue you are describing in your question:
object references an unsaved transient instance - save the transient instance before flushing
is caused by associating an entity in the state of New to an entity that's in the state of Managed.
This can happen when you are associating a child entity to a one-to-many collection in the parent entity, and the collection does not cascade
the entity state transitions.
So, you can fix this by adding cascade to the entity association that triggered this failure, as follows:
The @OneToOne
association
@OneToOne(
mappedBy = "post",
orphanRemoval = true,
cascade = CascadeType.ALL)
private PostDetails details;
Notice the
CascadeType.ALL
value we added for thecascade
attribute.
The @OneToMany
association
@OneToMany(
mappedBy = "post",
orphanRemoval = true,
cascade = CascadeType.ALL)
private List<Comment> comments = new ArrayList<>();
Again, the CascadeType.ALL
is suitable for the bidirectional @OneToMany
associations.
Now, in order for the cascade to work properly in a bidirectional, you also need to make sure that the parent and child associations are in sync.
The @ManyToMany
association
@ManyToMany(
mappedBy = "authors",
cascade = {
CascadeType.PERSIST,
CascadeType.MERGE
}
)
private List<Book> books = new ArrayList<>();
In a @ManyToMany
association, you cannot use CascadeType.ALL
or orphanRemoval
as this will propagate the delete entity state transition from one parent to another parent entity.
Therefore, for @ManyToMany
associations, you usually cascade the CascadeType.PERSIST
or CascadeType.MERGE
operations. Alternatively, you can expand that to DETACH
or REFRESH
.
Solution 4
This happens when saving an object when Hibernate thinks it needs to save an object that is associated with the one you are saving.
I had this problem and did not want to save changes to the referenced object so I wanted the cascade type to be NONE.
The trick is to ensure that the ID and VERSION in the referenced object is set so that Hibernate does not think that the referenced object is a new object that needs saving. This worked for me.
Look through all of the relationships in the class you are saving to work out the associated objects (and the associated objects of the associated objects) and ensure that the ID and VERSION is set in all objects of the object tree.
Solution 5
Or, if you want to use minimal "powers" (e.g. if you don't want a cascade delete) to achieve what you want, use
import org.hibernate.annotations.Cascade;
import org.hibernate.annotations.CascadeType;
...
@Cascade({CascadeType.SAVE_UPDATE})
private Set<Child> children;
Tushar Ahirrao
I know Javascript, HTML5, CSS3, Java, PHP and more.... I enjoy building things, learning programming languages, listening to music.
Updated on July 08, 2022Comments
-
Tushar Ahirrao almost 2 years
I receive following error when I save the object using Hibernate
object references an unsaved transient instance - save the transient instance before flushing
-
Marcus Leon about 14 yearsIsn't this implicit? Wouldn't you always want Hibernate to save them?
-
Bozho about 14 years@Marcus - no, it's not. You may want to handle them manually.
-
D3X over 13 yearsBozho is right. I've encountered circumstances where I've had collections that I wanted to manage manually because of their size, or because of business rules that don't allow all objects in a collection to get saved at the same time.
-
Sebastien Lorber almost 12 yearsIt doesn't happen only for collections but also simple one to one mappings
-
Sergii Shevchyk over 11 yearsWouldn't it be better to start with CascadeType.PERSIST and use persist to save?
-
Sanghyun Lee about 10 years@shevchik Using
CascadeType.PERSIST
didn't work for me. I hope someone explain the reason. -
elvin almost 10 yearsThis comment put me on the right track. I was assigning a new instance of the parent into a property of its child. So NH thought they were different instances.
-
CsBalazsHungary over 9 yearsSimilar problem to mine. Afterall, when I reloaded the entity locally, set the property, then saved, it worked fine.
-
Rori Stumpf over 9 yearsYes. This happens if, for example, the id of the associated object is not included (e.g. it's been ignored by @JsonIgnore). Hibernate has no way of identifying the associated entity, so it wants to save it.
-
Pooya about 9 yearsusing cascade='all' will re-insert parent. How can I avoid this? without cascade, It raises the above exception
-
Deadron about 9 yearsThis was totally my issue. I never would have guessed I had to manually set it to null.
-
xtian almost 8 yearsWhat if I don't want to cascade saves on a @OneToOne relationship? When creating both objects for the first time, how can I save either to the database without triggering the exception?
-
Fodder over 7 yearsThis was also my issue. I wasn't using a collection, so I didn't try this at first, but I set my object to null and now it works.
-
lilalinux over 7 yearsThis should be the accepted answer. CascadeType.ALL ist too broad
-
Omaruchan over 7 yearsWhat if I want to save the child for some cases and not for some others?
-
Chris311 over 7 yearsBut don't just add CascadeType.ALL without using your brain. You might have successor/predecessor of the same type! This would result in some kind of infinite loop.
-
Renato Mendes about 7 yearsis 100% correct, the Cascade.All is the lazy solution and only should be applied when required. first, if the entity already exists, check if it is loaded in the current entity manager, if not load it.
-
jcsahnwaldt Reinstate Monica about 7 yearsAs of Hibernate 5.2.8, there seems to be no way to achieve the same effect with JPA annotations. For example,
@ManyToMany(cascade={PERSIST, MERGE, REFRESH, DETACH})
(all but REMOVE) does not cascade updates like Hibernate'sCascadeType.SAVE_UPDATE
does. -
Anas almost 7 yearsI wish someone replies to @Pooya comment coz i have the same problem and looking for solution.
-
BML over 6 yearsThis should be a new question and it should be added as a bug, at least the misleading exception. This turned out to be the cause of my issue.
-
nespapu over 6 yearsHow do you know if a collection type rather than any other type?
-
vijay over 6 yearsCascade and transient are totally unrelated, infact the question doesn't carry any info about the context.
-
Sõber over 6 yearsIt is the opposite - child entity holds the FK value and depends on parent so you need to save parent first! In the code block you have it right.
-
kaba713 over 6 years@xtian: Well then you have to take care of the right order of saving to the database by persisting the objects with an EntityManager. In basic you just say em.persist(object1); em.persist(object2); etc.
-
Jim ReesPotter about 6 yearsI got this issue specifically when I used @Inheritance, in this case TABLE_PER_CLASS, I was referencing a subclass. CascadeType.ALL fixed it.
-
vipin cp about 6 yearswhat if its nullable?
-
Kenny almost 6 yearsFor anyone ever getting this error while using foreign keys: Cascade was not a solution for me as I did not want to store a collection in my parent-entity. All i wanted to do is save the id of another (foreign key) child-entity in my parent-entity. My problem seemed to be that I had used a "long" id in the child-entity, instead of a "Long" (lowercase vs uppercase). Sorry for bad use of words.
-
KasparTr over 5 yearsAdding 'cascade=CascadeType.ALL' fixes this error but introduces a new one when trying to save object created in different threads (using Async). Any ideas how these 2 can work together?
-
Gustavo over 5 yearsI have similar problem. I get the exception when my deptID is 0. Any other value greater than 0 works. Funny is that I have a dept with id = 0.
-
Christos Karapapas about 5 years@Bozho Having a OneToOne relation between two entities and keeping the child_id in parent entity and using Cascade.PERSIST on that property won't save the child and I get the Error of
object references an unsaved transient instance - save the transient instance before flushing
However, using Cascade.ALL on that property fixes the problem, saves the child and its id to the parent child_id property. Why is that? isn't the Cascade.PERSIST made exactly for that reason? Why should I use ALL, I was hoping to avoid the Cascade.DELETE for safety. -
Zon over 4 yearsOr you have created your entity object with
new MyEntity
(without synchronizing it to the database - flushing), instead of getting its synchronized instance from database. Making Hibernate queries using that instance informs you that what you expect to be in the database differs from what you have in your app's memory. In this case - simply synchronize/get your entity instabnce from DB and use it. No CascadeType.ALL is needed then. -
Jad Chahine over 4 yearsThis fixes my problem
-
theprogrammer over 4 yearsIf I do it this way, and save the parent entity, what's happening is there are two inserts in my parent table that is two rows. I think its because we have cascade on both parent and child entities?
-
ACV over 3 yearsHow does Hibernate determine that the instance is detached? Is it just looking at the ID and if it is null, it considers the instance detached or is there something else involved?
-
Vlad Mihalcea over 3 yearsFor merge, it runs a SELECT query. Otherwise, it checks the id and the version.
-
Sumit Rane about 3 yearsI was facing a problem similar to case 2, I have a C1 object reference in parent P1 object and C1 object is optional, I have to explicitly make C1 object null while saving P1 object when the user not adding C1 object.
-
PJ_Finnegan almost 3 yearsThanks! I had a foreign key referencing not the ID field on the referenced table, but a field with a UNIQUE constraint (CODE), and on creation Hibernate couldn't find the existing row from the given CODE and tried to create it on the referenced table. I solved by pre-fetching the whole entity (ID included) from its CODE, then putting into the Java entity before saving it. This time Hib didn't try to create the row and the error disappeared.
-
Islam Emam over 2 yearsYes you are right when I have added it in my entity it's working like a sharm
-
DeveloperKurt almost 2 yearsTotally missed the persisted entity in the ManyToOne field was persisted through a transactional call, adding @Transactional(propagation = Propagation.SUPPORTS) has solved my issue. Thanks.