-->
These old forums are deprecated now and set to read-only. We are waiting for you on our new forums!
More modern, Discourse-based and with GitHub/Google/Twitter authentication built-in.

All times are UTC - 5 hours [ DST ]



Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 13 posts ] 
Author Message
 Post subject: Detached Object Confused?
PostPosted: Fri Jan 18, 2008 3:47 am 
Newbie

Joined: Thu Jan 17, 2008 4:33 am
Posts: 8
I am reffering the following tutorial
http://www.hibernate.org/hib_docs/refer ... orial.html

In the method addPersonToEvent(Long personId, Long eventId)
if I replace the following statement

statement 1:
Person aPerson = (Person) session
.createQuery("select p from Person p left join fetch p.events
where p.id = :pid").setParameter("pid", personId).uniqueResult();

by

statement 2:
Person aPerson = (Person) session.load(Person.class, personId);

its not working.

Both are detached object, but why it is not working if i used statement 2.

Thanks in advance

Regards
Rakesh


Top
 Profile  
 
 Post subject: Re: Detached Object Confused?
PostPosted: Fri Jan 18, 2008 9:22 am 
Expert
Expert

Joined: Wed Apr 11, 2007 11:39 am
Posts: 735
Location: Montreal, QC
What is not working? You get an exception or the event is not added to person? Show me the whole code for this.


Farzad-


Top
 Profile  
 
 Post subject:
PostPosted: Tue Jan 22, 2008 4:58 am 
Newbie

Joined: Thu Jan 17, 2008 4:33 am
Posts: 8
public class Event {
private Long id;

private String title;
private Date date;

public Event() {}
}

<hibernate-mapping>

<class name="events.Event" table="EVENTS">
<id name="id" column="EVENT_ID">
<generator class="native"/>
</id>
<property name="date" type="timestamp" column="EVENT_DATE"/>
<property name="title"/>
</class>

</hibernate-mapping>


public class Person {

private Long id;
private int age;
private String firstname;
private String lastname;

private Set events = new HashSet();

public Person() {}

// Accessor methods for all properties

}

<hibernate-mapping>
<class name="events.Person" table="PERSON">
<id name="id" column="PERSON_ID">
<generator class="native"/>
</id>
<property name="age"/>
<property name="firstname"/>
<property name="lastname"/>

<set name="events" table="PERSON_EVENT">
<key column="PERSON_ID"/>
<many-to-many column="EVENT_ID" class="events.Event"/>
</set>

</class>
</hibernate-mapping>

hibernate.cfg.xml
-----------------------------------------------------------------------
<?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">

<hibernate-configuration>

<session-factory>

<!-- Database connection settings -->
<property name="connection.driver_class">org.hsqldb.jdbcDriver</property>
<property name="connection.url">jdbc:hsqldb:hsql://localhost</property>
<property name="connection.username">sa</property>
<property name="connection.password"></property>

<!-- JDBC connection pool (use the built-in) -->
<property name="connection.pool_size">1</property>

<!-- SQL dialect -->
<property name="dialect">org.hibernate.dialect.HSQLDialect</property>

<!-- Enable Hibernate's automatic session context management -->
<property name="current_session_context_class">thread</property>

<!-- Disable the second-level cache -->
<property name="cache.provider_class">org.hibernate.cache.NoCacheProvider</property>

<!-- Echo all executed SQL to stdout -->
<property name="show_sql">true</property>

<!-- Drop and re-create the database schema on startup -->
<property name="hbm2ddl.auto">create</property>

<mapping resource="events/Event.hbm.xml"/>
<mapping resource="events/Person.hbm.xml"/>

</session-factory>

</hibernate-configuration>


public class HibernateUtil {

private static final SessionFactory sessionFactory;

static {
try {
// Create the SessionFactory from hibernate.cfg.xml
sessionFactory = new Configuration().configure().buildSessionFactory();
} catch (Throwable ex) {
// Make sure you log the exception, as it might be swallowed
System.err.println("Initial SessionFactory creation failed." + ex);
throw new ExceptionInInitializerError(ex);
}
}

public static SessionFactory getSessionFactory() {
return sessionFactory;
}

}

public class EventManager {

public static void main(String[] args) {
EventManager mgr = new EventManager();

Long eventId = mgr.createAndStoreEvent("My Event", new Date());
Long personId = mgr.createAndStorePerson("Foo", "Bar");
mgr.addPersonToEvent(personId, eventId);
System.out.println("Added person " + personId + " to event " + eventId);
}


private Long createAndStoreEvent(String title, Date theDate) {

Session session = HibernateUtil.getSessionFactory().getCurrentSession();

session.beginTransaction();

Event theEvent = new Event();
theEvent.setTitle(title);
theEvent.setDate(theDate);

session.save(theEvent);

return theEvent.getId();
}

private Long createAndStorePerson(String firstName, Date lastName) {
.......

return thePerson.getId();
}



// This one is working
private void addPersonToEvent(Long personId, Long eventId) {

Session session = HibernateUtil.getSessionFactory().getCurrentSession();
session.beginTransaction();

Person aPerson = (Person) session
.createQuery("select p from Person p left join fetch p.events where p.id = :pid")
.setParameter("pid", personId)
.uniqueResult(); // Eager fetch the collection so we can use it detached

Event anEvent = (Event) session.load(Event.class, eventId);

session.getTransaction().commit();

// End of first unit of work

aPerson.getEvents().add(anEvent); // aPerson (and its collection) is detached

// Begin second unit of work

Session session2 = HibernateUtil.getSessionFactory().getCurrentSession();
session2.beginTransaction();

session2.update(aPerson); // Reattachment of aPerson

session2.getTransaction().commit();
}

// This one is not working... it throws an Exception "Could not initialize proxy - no Session"
private void addPersonToEvent(Long personId, Long eventId) {

Session session = HibernateUtil.getSessionFactory().getCurrentSession();
session.beginTransaction();

Person aPerson = (Person) session.load(Person.class, personId);
Event anEvent = (Event) session.load(Event.class, eventId);

session.getTransaction().commit();

// End of first unit of work

aPerson.getEvents().add(anEvent);

// Begin second unit of work

Session session2 = HibernateUtil.getSessionFactory().getCurrentSession();
session2.beginTransaction();

session2.update(aPerson);

session2.getTransaction().commit();

}

}


Top
 Profile  
 
 Post subject:
PostPosted: Tue Jan 22, 2008 10:56 am 
Newbie

Joined: Fri Jan 18, 2008 12:34 pm
Posts: 9
According to your sample and the exception you got, i think you tried to access a lazy-loaded relationship (getEvents) outside of the transaction scope. If you out lazy=false in the mapping definition, or call the getEvents() before closing the first transaction it shoud work better.


Top
 Profile  
 
 Post subject:
PostPosted: Tue Jan 22, 2008 11:50 am 
Newbie

Joined: Thu Jan 17, 2008 4:33 am
Posts: 8
Thanks for the quick response:

It works
1. Using statement 1, without placing aPerson.getEvents().add(anEvent) before closing the first transaction, and

2. If we put aPerson.getEvents().add(anEvent) before closing the first transaction. And no point of having the second transaction.

What is the difference between the following statements

statement 1:
Person aPerson = (Person) session
.createQuery("select p from Person p left join fetch p.events
where p.id = :pid").setParameter("pid", personId).uniqueResult();

statement 2:
Person aPerson = (Person) session.load(Person.class, personId);

Please correct me if I am wrong, In such situation we have to use only statement 1.


Top
 Profile  
 
 Post subject:
PostPosted: Tue Jan 22, 2008 12:00 pm 
Expert
Expert

Joined: Wed Apr 11, 2007 11:39 am
Posts: 735
Location: Montreal, QC
As the other guy pointed out it is a lazy initialization problem. The first example works because you are forcing collection initialization with join fetch command in HQL. However, in the second example a person is loaded by the API and it will not initialize the events collection, which indeed needs to be initialized in the same session the person itself is loaded. A session becomes invalid after its transaction commits so it can not be used to initialize the collection afterwards. What you need to do is to access the collection within the same transaction the person is loaded, and then you can modify it outside the scope of the first transaction:

Code:
private void addPersonToEvent(Long personId, Long eventId) {

Session session = HibernateUtil.getSessionFactory().getCurrentSession();
session.beginTransaction();

Person aPerson = (Person) session.load(Person.class, personId);
Event anEvent = (Event) session.load(Event.class, eventId);



aPerson.getEvents().size(); // it will initialize the collection so that it can be accessed later.

session.getTransaction().commit();

// End of first unit of work

aPerson.getEvents().add(anEvent);

// Begin second unit of work

Session session2 = HibernateUtil.getSessionFactory().getCurrentSession();
session2.beginTransaction();

session2.update(aPerson);

session2.getTransaction().commit();

}



Farzad-


Top
 Profile  
 
 Post subject:
PostPosted: Tue Jan 22, 2008 12:08 pm 
Expert
Expert

Joined: Wed Apr 11, 2007 11:39 am
Posts: 735
Location: Montreal, QC
Rakesk wrote:
Please correct me if I am wrong, In such situation we have to use only statement 1.


the first one is a HQL, a sort of object oriented equivalent to SQL, and it gives you more power it terms of mixing entities and filtering them. Lets say the same thing you would expect from SQL. The second one is a load by primary key sort of command which results in a SQL anyways but the only filtering criteria is primary key and optionally what is specified in a class's mapping. The second one uses the mapping instructions on what should be fetched and what shouldn't be fetched. Your mapping file is plain at the moment and it is using the defaults. You may want to step forward and put in some fetching strategies.


Farzad-


Top
 Profile  
 
 Post subject:
PostPosted: Wed Jan 23, 2008 6:16 am 
Newbie

Joined: Thu Jan 17, 2008 4:33 am
Posts: 8
Hi Farjad, Many thanks for your support ...


Top
 Profile  
 
 Post subject:
PostPosted: Wed Jan 23, 2008 6:53 am 
Newbie

Joined: Thu Jan 17, 2008 4:33 am
Posts: 8
private Long createAndStoreEvent(String title, Date theDate) {

Session session = HibernateUtil.getSessionFactory().getCurrentSession();

session.beginTransaction();

Event theEvent = new Event();
theEvent.setTitle(title);
theEvent.setDate(theDate);

session.save(theEvent);

return theEvent.getId();
}

Quote:
// Following code does not work ... it gives "Session is closed"
Long eventId = createAndStoreEvent("title", new Date());
Session session = HibernateUtil.getSessionFactory().getCurrentSession();
session.beginTransaction();

Event theEvent = (Event) session.load(Event.class, eventId);
session.getTransaction().commit();


Session session2 = HibernateUtil.getSessionFactory().getCurrentSession();
session2.beginTransaction();
theEvent.setTitle("some title");
session2.update(theEvent);
session2.getTransaction().commit();


When I try the above code, it throws an Exception "Session is closed". Why this is not working?

Thanks in advance.


Top
 Profile  
 
 Post subject:
PostPosted: Wed Jan 23, 2008 1:09 pm 
Expert
Expert

Joined: Wed Apr 11, 2007 11:39 am
Posts: 735
Location: Montreal, QC
It helps a lot more if you include the exception stack trace too. My rough guess here is that your session is bound to the running thread and since the first transaction commits it probably closes the session and the next time you get a (new) session it gives you the same instance since you are in the same thread context and bump, it explodes. Try creating a new session each time or change the session setting so that it is not bound to a thread.



Farzad-


Top
 Profile  
 
 Post subject:
PostPosted: Wed Jan 23, 2008 2:16 pm 
Newbie

Joined: Thu Jan 17, 2008 4:33 am
Posts: 8
Here the exception stack trace is

18:02:15,665 ERROR LazyInitializationException:19 - could not initialize proxy - the owning Session was closed
org.hibernate.LazyInitializationException: could not initialize proxy - the owning Session was closed
at org.hibernate.proxy.AbstractLazyInitializer.initialize(AbstractLazyInitializer.java:60)
at org.hibernate.proxy.AbstractLazyInitializer.getImplementation(AbstractLazyInitializer.java:111)
at org.hibernate.proxy.pojo.cglib.CGLIBLazyInitializer.invoke(CGLIBLazyInitializer.java:150)
at manytomany.Event$$EnhancerByCGLIB$$9efae8e6.setTitle(<generated>)
at detached.TestDetached.main(TestDetached.java:30)
Exception in thread "main" org.hibernate.LazyInitializationException: could not initialize proxy - the owning Session was closed
at org.hibernate.proxy.AbstractLazyInitializer.initialize(AbstractLazyInitializer.java:60)
at org.hibernate.proxy.AbstractLazyInitializer.getImplementation(AbstractLazyInitializer.java:111)
at org.hibernate.proxy.pojo.cglib.CGLIBLazyInitializer.invoke(CGLIBLazyInitializer.java:150)
at manytomany.Event$$EnhancerByCGLIB$$9efae8e6.setTitle(<generated>)
at detached.TestDetached.main(TestDetached.java:30)

It would helps a lot If you could tell
1. what are the rules (criteria) so that we could modify the detached object
2. which situations we could not modify the detached object.


Top
 Profile  
 
 Post subject:
PostPosted: Wed Jan 23, 2008 5:37 pm 
Expert
Expert

Joined: Wed Apr 11, 2007 11:39 am
Posts: 735
Location: Montreal, QC
Rakesk wrote:
It would helps a lot If you could tell
1. what are the rules (criteria) so that we could modify the detached object
2. which situations we could not modify the detached object.


the point here is that when you detach an object it can be initialized anymore so if you need to access something that is subject to initialization then you are doing an illegal action. Hibernate provides facilities by which you can make sure everything is initialized before something is going out of scope of a session. For more information look at "19.1.4. Initializing collections and proxies" in the hibernate document. Note, this is pretty much them same to when you cache objects. You will need to make sure things are initialized.



Farzad-


Top
 Profile  
 
 Post subject:
PostPosted: Thu Jan 24, 2008 2:48 am 
Newbie

Joined: Thu Jan 17, 2008 4:33 am
Posts: 8
Now am cleared my doubts... Many many thanks to you Farzad...


Top
 Profile  
 
Display posts from previous:  Sort by  
Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 13 posts ] 

All times are UTC - 5 hours [ DST ]


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum

Search for:
© Copyright 2014, Red Hat Inc. All rights reserved. JBoss and Hibernate are registered trademarks and servicemarks of Red Hat, Inc.