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:
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. Puttingupdatable=true
doesn't solve the problem.removing the
code
from theproperty
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).
- refactoring the combobox syntax, using
bean:define
instead ofc:forEach
- catching the exception and re-launching the same function when caught
- adding the list into the
currentPL
, this way the list gets retrieved correctly but, after saving or refreshing, it rethrows the same exception. - setting motivations on
null
by default, because maybe since there is not a motivation with anull
code, then Hibernate cannot find a Foreign Key, but nothing. - adding an auto-generated id column
- separating the two foreign keys in two separated entities
- 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?