How to fix the Hibernate "object references an unsaved transient instance - save the transient instance before flushing" error

827,135

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.

JPA entity states

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 the cascade 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;
Share:
827,135
Tushar Ahirrao
Author by

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, 2022

Comments

  • Tushar Ahirrao
    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
    Marcus Leon about 14 years
    Isn't this implicit? Wouldn't you always want Hibernate to save them?
  • Bozho
    Bozho about 14 years
    @Marcus - no, it's not. You may want to handle them manually.
  • D3X
    D3X over 13 years
    Bozho 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
    Sebastien Lorber almost 12 years
    It doesn't happen only for collections but also simple one to one mappings
  • Sergii Shevchyk
    Sergii Shevchyk over 11 years
    Wouldn't it be better to start with CascadeType.PERSIST and use persist to save?
  • Sanghyun Lee
    Sanghyun Lee about 10 years
    @shevchik Using CascadeType.PERSIST didn't work for me. I hope someone explain the reason.
  • elvin
    elvin almost 10 years
    This 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
    CsBalazsHungary over 9 years
    Similar problem to mine. Afterall, when I reloaded the entity locally, set the property, then saved, it worked fine.
  • Rori Stumpf
    Rori Stumpf over 9 years
    Yes. 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
    Pooya about 9 years
    using cascade='all' will re-insert parent. How can I avoid this? without cascade, It raises the above exception
  • Deadron
    Deadron about 9 years
    This was totally my issue. I never would have guessed I had to manually set it to null.
  • xtian
    xtian almost 8 years
    What 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
    Fodder over 7 years
    This 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
    lilalinux over 7 years
    This should be the accepted answer. CascadeType.ALL ist too broad
  • Omaruchan
    Omaruchan over 7 years
    What if I want to save the child for some cases and not for some others?
  • Chris311
    Chris311 over 7 years
    But 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
    Renato Mendes about 7 years
    is 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
    jcsahnwaldt Reinstate Monica about 7 years
    As 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's CascadeType.SAVE_UPDATE does.
  • Anas
    Anas almost 7 years
    I wish someone replies to @Pooya comment coz i have the same problem and looking for solution.
  • BML
    BML over 6 years
    This 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
    nespapu over 6 years
    How do you know if a collection type rather than any other type?
  • vijay
    vijay over 6 years
    Cascade and transient are totally unrelated, infact the question doesn't carry any info about the context.
  • Sõber
    Sõber over 6 years
    It 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
    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
    Jim ReesPotter about 6 years
    I 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
    vipin cp about 6 years
    what if its nullable?
  • Kenny
    Kenny almost 6 years
    For 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
    KasparTr over 5 years
    Adding '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
    Gustavo over 5 years
    I 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
    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
    Zon over 4 years
    Or 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
    Jad Chahine over 4 years
    This fixes my problem
  • theprogrammer
    theprogrammer over 4 years
    If 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
    ACV over 3 years
    How 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
    Vlad Mihalcea over 3 years
    For merge, it runs a SELECT query. Otherwise, it checks the id and the version.
  • Sumit Rane
    Sumit Rane about 3 years
    I 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
    PJ_Finnegan almost 3 years
    Thanks! 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
    Islam Emam over 2 years
    Yes you are right when I have added it in my entity it's working like a sharm
  • DeveloperKurt
    DeveloperKurt almost 2 years
    Totally missed the persisted entity in the ManyToOne field was persisted through a transactional call, adding @Transactional(propagation = Propagation.SUPPORTS) has solved my issue. Thanks.