Home > Mobile >  Hibernate throws exception, but only on first execution
Hibernate throws exception, but only on first execution

Time:12-05

I have an entity called Refund, which has two Foreign Keys on the same entity called Motivation.

Refund.java

// other columns

@ManyToOne(targetEntity=Motivation.class, optional=true, fetch=FetchType.LAZY)
@JoinColumn(name="opening_motivation", referencedColumnName="code")
@ForeignKey(name="REFUND_OPENING_MOTIVATION_FK")
private Motivation openingMotivation;

@ManyToOne(targetEntity=Motivation.class, optional=true, fetch=FetchType.LAZY)
@JoinColumn(name="closure_motivation", referencedColumnName="code")
@ForeignKey(name="REFUND_CLOSURE_MOTIVATION_FK")
private Motivation closureMotivation;

// getters and setters

Motivation.java

private String code;
private String type;
private String description;

// getters and setters

This class does not have annotations because it has an extend and it is automatically binded by Hibernate, in the hbm.xml. The @ManyToOne works flawlessly and the table is present and has some elements in the Database (which is Oracle).

Inside a JSP, i need to populate a combobox with the elements of this table, filtered by the type column.

As I do here:

MotivationDAO.java

public static List<Motivation> getMotivationsByType(String type) throws DatabaseException  {
    
    Criteria criteria = null;
    
    try {
        Session session = HibernateUtil.currentSession();
        
        criteria = session.createCriteria(Motivation.class);
        criteria.add(Restrictions.eq("type", type);
        return (List<Motivation>) criteria.list(); // the exception I specified later is thrown here
    
    } catch (HibernateException e) {
        throw new DatabaseException(e.getMessage());
    }catch (Exception e) {
        System.out.println("getMotivationList: "   e.getMessage());
        throw new DatabaseException("an error occured");
    }
}

and, in the JSP:

<form:select cssClass="comboBox" path="pageAction.currentPL.entity.openingMotivation.code" id="openingCombo" disabled="true">
    <form:option value=""></form:option>
    <c:forEach var="openingMotivation" items='<%=MotivationDAO.getMotivationsByType("A")%>'>            
        <form:option value="${openingMotivation.code}">${openingMotivation.code} - ${openingMotivation.description}</form:option>
    </c:forEach>
</form:select>

The problem is: for some Refunds (that has absolutely nothing different with "working" ones), the getMotivationsByType() functions gives an exception: object references an unsaved transient instance - save the transient instance before flushing. I tried browsing the Internet and I found this article. After applying the fix, it still gives me an error, but a different exception: ids for this class must be manually assigned before calling save(). Again, tried browsing and found this post, but it suggests to add an auto-increment column Id for the class. This is not what I need, plus, I can not add it.

The strange fact is that if I refresh the JSP on the same "bugged" Refund, it works flawlessly. I tried some fixes which also actually fix the problem, but then I get some regressions on the save, like:

  1. adding some properties to the foreign key annotations, for example: updatable=false.. But it doesn't work to me, because the field must be updatable. Putting updatable=true doesn't solve the problem.

  2. removing the code from the property in the combobox path, like so:

    <form:select cssClass="comboBox" path="pageAction.currentPL.entity.openingMotivation" id="openingCombo" disabled="true">
        <form:option value=""></form:option>
        <c:forEach var="openingMotivation" items='<%=MotivationDAO.getMotivationsByType("A")%>'>            
            <form:option value="${openingMotivation}">${openingMotivation.code} - ${openingMotivation.description}</form:option>
        </c:forEach>
    </form:select>
    

to send the full Entity to the backend, but it does not (entity appears to be null).

  1. refactoring the combobox syntax, using bean:define instead of c:forEach
  2. catching the exception and re-launching the same function when caught
  3. adding the list into the currentPL, this way the list gets retrieved correctly but, after saving or refreshing, it rethrows the same exception.
  4. setting motivations on null by default, because maybe since there is not a motivation with a null code, then Hibernate cannot find a Foreign Key, but nothing.
  5. adding an auto-generated id column
  6. separating the two foreign keys in two separated entities
  7. closing the hibernate session

What is unclear to me is: why does it solve the problem if I change a completely separated snippet of code? And why does it work on the second round?

Thanks in advance to whoever is willing to help!

CodePudding user response:

This is not a proper solution, but I discovered that the problem is caused by Sessions and Threads. In this project, it is used an internal method to retrieve the Hibernate current session using Threads. By changing the Thread number, the exception gets thrown in the next instance where this current session is used. So, if you are having the same problem, try investigating about these things.

  • Related