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

Nathan Bryant (JIRA) noreply at atlassian.com
Wed Mar 24 17:50:32 EDT 2010


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

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.jspa
-
For more information on JIRA, see: http://www.atlassian.com/software/jira

        


More information about the hibernate-issues mailing list