]
Carl-Eric Menzel commented on HHH-5299:
---------------------------------------
I haven't had time to test it yet, but the patch in HHH-1870 doesn't seem to me to
be a good way to address this.
Also, this issue is not *fixed* by HHH-1870 either, since that is still unresolved and
points to Hibernate 4, so that looks more like a "won't fix" to me.
I'm going to check this with core-only instead of entity manager, though I can't
really see how that would affect this particular bug.
In any case, I'd appreciate it if someone could have a look at this patch I provided
last year and hopefully apply it to a 3.x release.
Multi-Level cascading of unsaved instances with bidirectional
associations fails with TransientObjectException
--------------------------------------------------------------------------------------------------------------
Key: HHH-5299
URL:
http://opensource.atlassian.com/projects/hibernate/browse/HHH-5299
Project: Hibernate Core
Issue Type: Bug
Components: core
Affects Versions: 3.3.2, 3.5.4, 3.6.0.Beta1
Environment: Tested with OracleXE and H2DB, Hibernate Core 3.3.2, Hibernate
Entity Manager 3.4.0
Reporter: Carl-Eric Menzel
Assignee: Gail Badner
Priority: Critical
Attachments: 0001-fixed-no-cascading-check-to-also-accept-entities-wit.patch,
cascadetest.zip
Given the following classes (pseudocode, full source in the attached zipfile):
Top {
@OneToMany(cascade = { CascadeType.ALL }, mappedBy = "top")
List<Middle> middles
}
Middle {
@ManyToOne
Top top
@OneToOne(cascade = { CascadeType.ALL })
@JoinColumn(name = "BOTTOM_ID")
Bottom bottom
}
Bottom {
@OneToOne(mappedBy = "bottom")
Middle middle
}
The following code fails on the second flush with a TransientObjectException:
Top top = new Top();
em.persist(top);
em.flush();
// top is now attached, status MANAGED
Middle middle = new Middle(1l);
middle.setBottom(new Bottom());
top.addMiddle(middle);
Middle middle2 = new Middle(2l);
middle2.setBottom(new Bottom());
top.addMiddle(middle2);
// both middles and bottoms are transient but should be saved by cascade
em.flush(); // boom!
The relevant part of the error is:
org.hibernate.TransientObjectException: object references an unsaved transient instance -
save the transient instance before flushing: test.Bottom.middle -> test.Middle
at org.hibernate.engine.CascadingAction$9.noCascade(CascadingAction.java:376)
at org.hibernate.engine.Cascade.cascade(Cascade.java:163)
The same code works without exception when using EclipseLink instead of Hibernate
EntityManager, so I am assuming that the test code is valid.
Some debugging revealed that CascadingAction.PERSIST_ON_FLUSH.noCascade() checks the
inverse association from Bottom to Middle. It then calls a private method isInManagedState
to verify that this association does not reference an unsaved instance. It does this by
checking the entities EntityEntry.getStatus() value, which it expects to be MANAGED or
READ_ONLY. At this time, however, the Middle instance is in the middle (no pun intended)
of its own cascading save cycle and therefore its status is SAVING. This, to me, seems to
be a valid session-attached status, so isInManagedState() should also accept this state.
The attached patch against Hibernate Core 3.3.2 implements just that, and this change
makes the above example code work as expected. The Hibernate test suite did not complain,
so I am reasonably sure I did not break anything else.
See also the attached cascadetest.zip for a ready-to-use testcase that demonstrates the
error with Hibernate Core 3.3.2. Change the dependency in the supplied pom.xml to a
patched version of Hibernate Core, and the test will no longer fail.
Carl-Eric Menzel
C1 SetCon GmbH
--
This message is automatically generated by JIRA.
For more information on JIRA, see: