[
http://opensource.atlassian.com/projects/hibernate/browse/HHH-2341?page=c...
]
Nathan Bryant commented on HHH-2341:
------------------------------------
Although I don't know what the JPA spec has to say about this corner case, if
anything, I believe this should be closed as not a bug, for the following reasons:
* It's caused by invalid referential integrity in the database - essentially
"user error." It's difficult for hibernate to behave correctly in the face
of this sort of thing; when loading the foreign key column from the database, there's
no field in the entity in which to preserve the state of the column, unless multiple
mappings are defined, so the results when the entity is later persisted appear to be
undefined.
* It relates to documented behavior: the @NotFoundAction annotation can be added to get
the desired effect of allowing the child entity to load, while an attempt to get the
parent will simply return null. @NotFoundAction is documented to have a default
action=EXCEPTION.
* Another workaround exists, which is to use fetch=LAZY for the property in question. (See
also HHH-3917, which is kind of interesting...)
ObjectNotFoundException on session.get() on non-existent object
---------------------------------------------------------------
Key: HHH-2341
URL:
http://opensource.atlassian.com/projects/hibernate/browse/HHH-2341
Project: Hibernate Core
Issue Type: Bug
Components: core
Affects Versions: 3.2.1
Environment: HSQLDB 1.8.0
Reporter: Timo Thomas
Attachments: TestHibernateCascade.zip
Hibernate version:
3.2.1 GA (same for hibernate-annotations)
Mapping documents:
Parent.java (omitting package and some import declarations)
import javax.persistence.*;
@Entity
public class Parent {
public Integer id;
public Set<Child> children = new HashSet<Child>();
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
@OneToMany(mappedBy = "parent", cascade = CascadeType.ALL)
public Set<Child> getChildren() {
return children;
}
public void setChildren(Set<Child> children) {
this.children = children;
}
}
Child.java (omitting package and some import declarations)
import javax.persistence.*;
@Entity
public class Child {
public Integer id;
public Parent parent;
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
@ManyToOne(optional = false)
@JoinColumn(name = "parent_fk")
public Parent getParent() {
return parent;
}
public void setParent(Parent parent) {
this.parent = parent;
}
}
Code between sessionFactory.openSession() and session.close():
Transaction transaction = session.beginTransaction();
Parent parent = new Parent();
parent.setName("p1");
session.persist(parent);
assertNotNull(parent.getId());
Integer parentId = parent.getId();
Child child = new Child();
child.setName("c1");
child.setParent(parent);
parent.getChildren().add(child);
session.persist(parent);
assertNotNull(child.getId());
Integer childId = child.getId();
transaction.commit();
session.close();
///////////////////////////////////////////
session = sessionFactory.openSession();
transaction = session.beginTransaction();
parent = (Parent) session.load(Parent.class, parentId);
child = (Child) session.load(Child.class, childId);
// child = (Child) session.get(Child.class, childId);
session.delete(parent);
// session.flush(); // !! required if session&transaction is re-opened and
child is obtained with load(), otherwise exception on next line - BUG ?
child = (Child) session.get(Child.class, childId);
Full stack trace of any exception that occurs:
org.hibernate.ObjectNotFoundException: No row with the given identifier exists:
[model.Child#1]
at
org.hibernate.impl.SessionFactoryImpl$1.handleEntityNotFound(SessionFactoryImpl.java:375)
at
org.hibernate.event.def.DefaultLoadEventListener.returnNarrowedProxy(DefaultLoadEventListener.java:223)
at
org.hibernate.event.def.DefaultLoadEventListener.proxyOrLoad(DefaultLoadEventListener.java:187)
at
org.hibernate.event.def.DefaultLoadEventListener.onLoad(DefaultLoadEventListener.java:103)
at org.hibernate.impl.SessionImpl.fireLoad(SessionImpl.java:878)
at org.hibernate.impl.SessionImpl.get(SessionImpl.java:815)
at org.hibernate.impl.SessionImpl.get(SessionImpl.java:808)
at test.CascadeAnnotationTest.testBug(CascadeAnnotationTest.java:48)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at
sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:585)
at junit.framework.TestCase.runTest(TestCase.java:164)
at junit.framework.TestCase.runBare(TestCase.java:130)
at junit.framework.TestResult$1.protect(TestResult.java:110)
at junit.framework.TestResult.runProtected(TestResult.java:128)
at junit.framework.TestResult.run(TestResult.java:113)
at junit.framework.TestCase.run(TestCase.java:120)
at junit.framework.TestSuite.runTest(TestSuite.java:228)
at junit.framework.TestSuite.run(TestSuite.java:223)
at org.junit.internal.runners.OldTestClassRunner.run(OldTestClassRunner.java:35)
at
org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:38)
at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
at
org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:460)
at
org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:673)
at
org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:386)
at
org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:196)
The generated SQL (show_sql=true):
Hibernate: insert into Parent (id, name) values (null, ?)
Hibernate: call identity()
Hibernate: insert into Child (id, name, parent_fk) values (null, ?, ?)
Hibernate: call identity()
Hibernate: select parent0_.id as id0_0_, parent0_.name as name0_0_ from Parent parent0_
where parent0_.id=?
Hibernate: select children0_.parent_fk as parent3_1_, children0_.id as id1_,
children0_.id as id1_0_, children0_.name as name1_0_, children0_.parent_fk as parent3_1_0_
from Child children0_ where children0_.parent_fk=?
Why is this exception thrown under these circumstances? Am I using the API in an
undocumented/disallowed way? If yes, where exactly?
The Hibernate API doc says, that Session.get() returns null if an object can't be
found. No exception should be thrown.
However, Session.get() at the end of sample code does return null as expected, if either
a) Session.get() is used instead of load() some lines above (see commented line)
b) the transaction and the session is isn't closed or reopened, respectively
c) Session.flush() is called before the final call to Session.get()
I'd like to understand why Hibernate behaves like this, which I presume is erroneous.
I'm a beginner in Hibernate, but I couldn't get any help in the forum.
Timo
--
This message is automatically generated by JIRA.
-
If you think it was sent incorrectly contact one of the administrators:
http://opensource.atlassian.com/projects/hibernate/secure/Administrators....
-
For more information on JIRA, see:
http://www.atlassian.com/software/jira