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

前端 未结 30 1146
既然无缘
既然无缘 2020-11-22 07:11

I receive following error when I save the object using Hibernate

object references an unsaved transient instance - save the transient instance before flushi         


        
相关标签:
30条回答
  • 2020-11-22 07:34

    beside all other good answers, this could happen if you use merge to persist an object and accidentally forget to use merged reference of the object in the parent class. consider the following example

    merge(A);
    B.setA(A);
    persist(B);
    

    In this case, you merge A but forget to use merged object of A. to solve the problem you must rewrite the code like this.

    A=merge(A);//difference is here
    B.setA(A);
    persist(B);
    
    0 讨论(0)
  • 2020-11-22 07:35

    Case 1: I was getting this exception when I was trying to create a parent and saving that parent reference to its child and then some other DELETE/UPDATE query(JPQL). So I just flush() the newly created entity after creating parent and after creating child using same parent reference. It Worked for me.

    Case 2:

    Parent class

    public class Reference implements Serializable {
    
        @Id
        @Column(precision=20, scale=0)
        private BigInteger id;
    
        @Temporal(TemporalType.TIMESTAMP)
        private Date modifiedOn;
    
        @OneToOne(mappedBy="reference")
        private ReferenceAdditionalDetails refAddDetails;
        . 
        .
        .
    }
    

    Child Class:

    public class ReferenceAdditionalDetails implements Serializable{
    
        private static final long serialVersionUID = 1L;
    
        @Id
        @OneToOne
        @JoinColumn(name="reference",referencedColumnName="id")
        private Reference reference;
    
        private String preferedSector1;
        private String preferedSector2;
        .
        .
    
    }
    

    In the above case where parent(Reference) and child(ReferenceAdditionalDetails) having OneToOne relationship and when you try to create Reference entity and then its child(ReferenceAdditionalDetails), it will give you the same exception. So to avoid the exception you have to set null for child class and then create the parent.(Sample Code)

    .
    .
    reference.setRefAddDetails(null);
    reference = referenceDao.create(reference);
    entityManager.flush();
    .
    .
    
    0 讨论(0)
  • 2020-11-22 07:39

    One other possible reason: in my case, I was attempting to save the child before saving the parent, on a brand new entity.

    The code was something like this in a User.java model:

    this.lastName = lastName;
    this.isAdmin = isAdmin;
    this.accountStatus = "Active";
    this.setNewPassword(password);
    this.timeJoin = new Date();
    create();
    

    The setNewPassword() method creates a PasswordHistory record and adds it to the history collection in User. Since the create() statement hadn't been executed yet for the parent, it was trying to save to a collection of an entity that hadn't yet been created. All I had to do to fix it was to move the setNewPassword() call after the call to create().

    this.lastName = lastName;
    this.isAdmin = isAdmin;
    this.accountStatus = "Active";
    this.timeJoin = new Date();
    create();
    this.setNewPassword(password);
    
    0 讨论(0)
  • 2020-11-22 07:40

    Introduction

    As I explained in this article 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, as I explained in this article, 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.

    Check out this article for more details about what is the best way to achieve this goal.

    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.

    For more details about the best way to map a @ManyToMany association, check out this article as well.

    0 讨论(0)
  • 2020-11-22 07:43

    To add my 2 cents, I got this same issue when I m accidentally sending null as the ID. Below code depicts my scenario (and OP didn't mention any specific scenario).

    Employee emp = new Employee();
    emp.setDept(new Dept(deptId)); // --> when deptId PKID is null, same error will be thrown
    // calls to other setters...
    em.persist(emp);
    

    Here I m setting the existing department id to a new employee instance without actually getting the department entity first, as I don't want to another select query to fire.

    In some scenarios, deptId PKID is coming as null from calling method and I m getting the same error.

    So, watch for null values for PK ID

    0 讨论(0)
  • 2020-11-22 07:43

    In my case , issue was completely different. I have two classes let's say c1 & c2. Between C1 & C2 dependency is OneToMany. Now if i am saving C1 in DB it was throwing above error.

    Resolution of this problem was to get first C2's id from consumer request and find C2 via repository call.Afterwards save c2 into C1 object .Now if i am saving C1, it's working fine.

    0 讨论(0)
提交回复
热议问题