5 Replies Latest reply on Feb 26, 2009 4:05 AM by Stuart Douglas

    production error - java.lang.IllegalStateException: org.hibernate.TransientObjectException: object references an unsaved transient instance - save the transient instance before flushing

    Val Sw Expert
      All of a sudden we got this error on production while calling projectHome.persist()

      When I tried to create project again by calling projectHome.persist(), it worked.
      Why it is that this is random error.

      Please suggest as it is in production, below is the log and entity in question.

      Error log:
      ---------
      java.lang.IllegalStateException: org.hibernate.TransientObjectException: object references an unsaved transient instance - save the transient instance before flushing: com.entity.QuantExperimentHistoryRecords.project -> com.entity.Project
           at org.hibernate.ejb.AbstractEntityManagerImpl.throwPersistenceException(AbstractEntityManagerImpl.java:626)
           at org.hibernate.ejb.QueryImpl.getSingleResult(QueryImpl.java:99)
           at com.session.ProjectHome.getUsers(Unknown Source)
           at com.session.ProjectHome.persist(Unknown Source)
      at org.jboss.seam.servlet.SeamFilter$FilterChainImpl.doFilter(SeamFilter.java:83)
           at org.jboss.seam.web.MultipartFilter.doFilter(MultipartFilter.java:85)
           at org.jboss.seam.servlet.SeamFilter$FilterChainImpl.doFilter(SeamFilter.java:69)
           at org.jboss.seam.web.ExceptionFilter.doFilter(ExceptionFilter.java:64)
           at org.jboss.seam.servlet.SeamFilter$FilterChainImpl.doFilter(SeamFilter.java:69)
           at org.jboss.seam.web.RedirectFilter.doFilter(RedirectFilter.java:45)
           at org.jboss.seam.servlet.SeamFilter$FilterChainImpl.doFilter(SeamFilter.java:69)
           .....
      Caused by: org.hibernate.TransientObjectException: object references an unsaved transient instance - save the transient instance before flushing: com.entity.QuantExperimentHistoryRecords.project -> com.entity.Project
           at org.hibernate.engine.CascadingAction$9.noCascade(CascadingAction.java:353)
           at org.hibernate.engine.Cascade.cascade(Cascade.java:139)
           at org.hibernate.event.def.AbstractSaveEventListener.cascadeBeforeSave(AbstractSaveEventListener.java:431)
           at org.hibernate.event.def.AbstractSaveEventListener.performSaveOrReplicate(AbstractSaveEventListener.java:265)
           at org.hibernate.event.def.AbstractSaveEventListener.performSave(AbstractSaveEventListener.java:181)
           at org.hibernate.event.def.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:121)
           ....

      @Entity(name = "Project")
      public class Project implements Equals, HashCode, ToString {
           protected List<QuantExperimentHistoryRecords> quantExperimentHistoryRecords;

           @OneToMany(cascade = {CascadeType.ALL}, fetch = FetchType.LAZY, mappedBy="project")
          public List<QuantExperimentHistoryRecords> getQuantExperimentHistoryRecords() {
              if (quantExperimentHistoryRecords == null) {
                  quantExperimentHistoryRecords = new ArrayList<QuantExperimentHistoryRecords>();
              }
              return this.quantExperimentHistoryRecords;
          }
           ..setter
      }

      @Entity(name = "QuantExperimentHistoryRecords")
      public class QuantExperimentHistoryRecords implements Equals, HashCode, ToString {
           protected Project project;

           @ManyToOne(fetch = FetchType.LAZY, optional=false)
          public Project getProject() {
              return project;
          }
           ..setter
      }
        • 1. Re: production error - java.lang.IllegalStateException: org.hibernate.TransientObjectException: object references an unsaved transient instance - save the transient instance before flushing
          Stuart Douglas Master

          The project field in QuantExperimentHistoryRecords is either not an entity or null. When you add one to project.quantExperimentHistoryRecords make sure you set the projet field. You are going to have to post some more code if you want more info.

          • 2. Re: production error - java.lang.IllegalStateException: org.hibernate.TransientObjectException: object references an unsaved transient instance - save the transient instance before flushing
            Val Sw Expert
            Thanks for replying, here are the details :

            We are storing History data in QuantExperimentHistoryRecords on any Project create or Experiment create.
            History table columns : ACTION_DATE, ACTION_TYPE, USERID, USERS_HJID, PROJECT_HJID, QUANTEXPERIMENT_HJID

            I tried to re-produce the error but I am not getting any exception, it is important to know why it happened.

            Below is projectHome.persist(), Project and QuantExperimentHistoryRecords entity.

            Please suggest.

            ProjectHome.java
            ----------------
            public String persist(){
                 java.util.ArrayList<QuantExperiment> arrListQuantExp=new java.util.ArrayList<QuantExperiment>();
                 QuantExperiment qe=quantExperimentHome.getInstance();
                 
                 
                 ArrayList<QuantExperimentHistoryRecords> arrListQuantExperimentHistoryRecords=new ArrayList<QuantExperimentHistoryRecords>();
                 arrListQuantExperimentHistoryRecords.add(createNewQuantExperimentHistoryRecords
                           (QuantExperimentHistoryRecords.CREATE_PROJECT,
                           checkUsers.getUsers(),
                           quantExperimentHome,
                           this.getInstance()));
                 ......
                 qe.setQuantExperimentHistoryRecords(arrListQuantExperimentHistoryRecords);
                 return super.persist();
            }

            private static QuantExperimentHistoryRecords createNewQuantExperimentHistoryRecords(String action,Users user,          QuantExperimentHome qe,Project project){
                     QuantExperimentHistoryRecords qehr=new QuantExperimentHistoryRecords();
                           qehr.setActionType(action);
                           qehr.setActionDate(new java.util.Date());
                           qehr.setUsers(user);
                           qehr.setQuantExperiment(qe.getInstance());
                           qehr.setProject(project);
                           qehr.setUserID(user.getUserId());          
                      return qehr;
                }     

            QuantExperimentHistoryRecords Entity :
            --------------------------------------
            public class QuantExperimentHistoryRecords implements Equals, HashCode, ToString
                 {
                      protected Project project;
                      protected QuantExperiment quantExperiment;

                      @ManyToOne(fetch = FetchType.LAZY, optional=false)
                      public Project getProject() {
                           return project;
                      }

                      @ManyToOne(fetch = FetchType.LAZY, optional=false)
                      public QuantExperiment getQuantExperiment() {
                           return quantExperiment;
                      }

            Project Entity :
            --------------
            • 3. Re: production error - java.lang.IllegalStateException: org.hibernate.TransientObjectException: object references an unsaved transient instance - save the transient instance before flushing
              Stuart Douglas Master

              The exception occurred when getUsers() was called, in the query flush. Depending on the flush mode, sometimes the persistence provider will flush the persistence context before every query. The reason for your error is that there was a QuantExperiment or a Project in the persistence context that references a new QuantExperimentHistoryRecords that has not had its project field set yet, so when the persistence context is flushed an exception is thrown.


              I think that this is happening somewhere else, maybe in getUsers() or in quantExperimentHome.getInstance(), can you post these?


              Is the persist method being called direct from the EL or is it being invoked by another method? If it is being invoked by another method post that code as well.


              Stuart

              • 4. Re: production error - java.lang.IllegalStateException: org.hibernate.TransientObjectException: object references an unsaved transient instance - save the transient instance before flushing
                Val Sw Expert
                First of all thanks a lot for looking into it.

                a) I am using this.getUsers() in persist, which will return logged-in user (sorry for posting persist code block again, just wanted to clarify)

                b) quantExperimentHome.getInstance() is default as generated by seam.

                c) projectHome.persist() is directly invoked from xhtml
                     <h:commandLink id="save" value="Save Project"
                           action="#{projectHome.persist}"
                        disabled="#{!projectHome.wired}"
                        rendered="#{!projectHome.managed}"/>

                d) Do you think using flush mode manual to persist will be of any help...
                "@Begin(join=true, flushMode=org.jboss.seam.annotations.FlushModeType.MANUAL)"

                e) Our entity hierarchy is Project have list of QuantExperimentHistoryRecords and QuantExperiment.
                   Similarly QuantExperiment entity have list of QuantExperimentHistoryRecords, as we needed to track history for any project create or experiment create.

                Problem is it happened first time today since last 4 months ...

                @Entity(name = "Project")
                -------------------------
                public class Project implements Equals, HashCode, ToString {

                protected List<QuantExperimentHistoryRecords> quantExperimentHistoryRecords;
                protected List<QuantExperiment> quantExperiment;

                @OneToMany(cascade = {CascadeType.ALL}, fetch = FetchType.LAZY, mappedBy="project")
                    public List<QuantExperimentHistoryRecords> getQuantExperimentHistoryRecords() {
                        if (quantExperimentHistoryRecords == null) {
                            quantExperimentHistoryRecords = new ArrayList<QuantExperimentHistoryRecords>();
                        }
                        return this.quantExperimentHistoryRecords;
                    }
                ..setter
                }

                @OneToMany(cascade = {CascadeType.ALL},fetch=FetchType.LAZY, mappedBy="project")
                public List<QuantExperiment> getQuantExperiment() {
                     if (quantExperiment == null) {
                          quantExperiment = new ArrayList<QuantExperiment>();
                     }
                     return this.quantExperiment;
                }

                ProjectHome.java
                ----------------
                @Out(required=false)
                @In(required=false)     
                QuantExperimentHome quantExperimentHome=new QuantExperimentHome();

                public String persist(){          
                     java.util.ArrayList<QuantExperiment> arrListQuantExp=new java.util.ArrayList<QuantExperiment>();
                     QuantExperiment qe=quantExperimentHome.getInstance();
                     ArrayList<QuantExperimentHistoryRecords> arrListQuantExperimentHistoryRecords=new ArrayList<QuantExperimentHistoryRecords>();
                     arrListQuantExperimentHistoryRecords.add(createNewQuantExperimentHistoryRecords
                     (QuantExperimentHistoryRecords.CREATE_PROJECT,
                     this.getUsers(),
                     quantExperimentHome,
                     this.getInstance()));
                     ......
                     qe.setQuantExperimentHistoryRecords(arrListQuantExperimentHistoryRecords);
                     return super.persist();
                }

                public Users getUsers() {          
                          Users users = (Users)entityManager.createQuery("from Users where userid = :userid")
                                         .setParameter("userid", identity.getUsername().toLowerCase())
                                                   .getSingleResult();
                          return users;
                     }

                QuantExperimentHome.java
                ------------------------
                @Name("quantExperimentHome")
                public class QuantExperimentHome extends EntityHome<QuantExperiment> {
                     @Override
                     protected QuantExperiment createInstance() {
                          QuantExperiment quantExperiment = new QuantExperiment();
                          return quantExperiment;
                     }
                     public void wire() {
                          getInstance();
                          Project project = projectHome.getDefinedInstance();
                          if (project != null) {
                               getInstance().setProject(project);
                          }
                     }
                • 5. Re: production error - java.lang.IllegalStateException: org.hibernate.TransientObjectException: object references an unsaved transient instance - save the transient instance before flushing
                  Stuart Douglas Master

                  That is very weird, the Exception refers to QuantExperimentHistoryRecords.project, however it occurs in the call to getUsers, before any of these are created, which is impossible. Because you are using auto flush mode we know the session was flushed after the previous request, so there is no chance a previous request left a transient object in the persistence context and did not flush, which is all quite strange.


                  Do you call getUsers in the section of persist() that you ommited? That is the only explanation that I can think of right now.