[hibernate-issues] [Hibernate-JIRA] Commented: (HHH-2341) ObjectNotFoundException on session.get() on non-existent object

Zach Bailey (JIRA) noreply at atlassian.com
Tue Sep 4 13:43:14 EDT 2007


    [ http://opensource.atlassian.com/projects/hibernate/browse/HHH-2341?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel#action_28010 ] 

Zach Bailey commented on HHH-2341:
----------------------------------

We are also seeing this issue. We were surprised by it as well because the documentation clearly states the desired behavior (from our end) and there is no mention of ONFE being thrown.

We have done some searching around and found this issue: HHH-1714.

Basically the behavior seems to be that when the object has already been loaded into the session, the object's "identifier" is associated with the session based on the primary key field and the object's type. Then, when we do a get() with a different type, but the same primary key, it already knows about the proxy in the session and throws the ONFE. This is clearly exhibited by polymorphic associations.

For instance, create the following objects in your domain:

A (abstract)
B (extends A)
C (extends A)
D (has a relationship to A)

Create D and assign an object of type either B or C. Save D. Fetch D and initialize the association to A, loading a proxy into the session. Then query for an asset of the opposite type that D is associated to, using get() and the concrete/leaf node type. In this situation, an ONFE will be thrown, which conflicts with the documentation for this method. If instead get() with the abstract class (A) is used (a polymorphic query), the correct behavior will be preserved: you will get back B or C.



> ObjectNotFoundException on session.get() on non-existent object
> ---------------------------------------------------------------
>
>                 Key: HHH-2341
>                 URL: http://opensource.atlassian.com/projects/hibernate/browse/HHH-2341
>             Project: Hibernate3
>          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.jspa
-
For more information on JIRA, see: http://www.atlassian.com/software/jira

        



More information about the hibernate-issues mailing list