Search This Blog

Monday, 19 March 2012

From Detached to Removed

In our previous post we saw how to transition a detached object back to a persistent state. Is it possible to delete an entity from the database if it is not associated with any session? Would Hibernate throw an exception or would the delete succeed? Or would the code simply crash ? The best way to be sure is to try it out on our own :
public static void deleteTransient() {
    Session session1 = sessionFactory.openSession();
    Entity entity = new Entity(); 
    entity.setData("Temp Object");        
    Transaction transaction = session1.beginTransaction();
    final Integer id = (Integer) session1.save(entity);
    System.out.println("The id is " + id);
    // Object will be now be saved to the db
    transaction.commit();
    session1.close();
    //The object is now detached

    Session session2 = sessionFactory.openSession();
    transaction = session2.beginTransaction();
    session2.delete(entity);
    //The object is now removed
    transaction.commit();
    session2.close();
    System.out.println("The id is " + entity.getId());
}
Here we have created an object that is initially in the transient state. We then saved it to the database moving it to a persistent state.
On closing the session, the persistent object is now detached. We then open a new session and attempt to delete the transient object without re-attaching it to the session.
2407 [main] DEBUG org.hibernate.SQL  - 
    insert 
    into
        Entity
        (DATA) 
    values
        (?)
The id is 9
...
2469 [main] DEBUG org.hibernate.impl.SessionImpl  - after transaction completion
2469 [main] DEBUG org.hibernate.impl.SessionImpl  - closing session
...
2532 [main] DEBUG org.hibernate.persister.entity.AbstractEntityPersister  - Dele
ting entity: [com.model.Entity#9]
2532 [main] DEBUG org.hibernate.jdbc.AbstractBatcher  - about to open PreparedSt
atement (open PreparedStatements: 0, globally: 0)
2532 [main] DEBUG org.hibernate.SQL  - 
    delete 
    from
        Entity 
    where
        id=?
2578 [main] DEBUG org.hibernate.impl.SessionImpl  - after transaction completion
2578 [main] DEBUG org.hibernate.impl.SessionImpl  - closing session
The id is null
As can be seen the object was created successfully in the first session and then also deleted successfully in session number two.Thus the delete method  takes care of two steps:
  1. It reattaches the detached object to the session.
  2. It then schedules the object for deletion.
Thus to delete objects, there is no need to manually reattach them to the session.
Would this code work ?
public static void deleteUnloaded() {
    Session session1 = sessionFactory.openSession();
    Entity entity = new Entity(); 
    entity.setData("Temp Object");        
    Transaction transaction = session1.beginTransaction();
    session1.delete(entity);
    transaction.commit();
    session1.close();
}
I took a new object and tried to delete it. The logs are as follows:
2265 [main] DEBUG org.hibernate.jdbc.JDBCContext  - after transaction begin
2281 [main] DEBUG org.hibernate.event.def.DefaultDeleteEventListener  - entity w
as not persistent in delete processing
2297 [main] INFO  org.hibernate.event.def.DefaultDeleteEventListener  - handling
 transient entity in delete processing
2297 [main] DEBUG org.hibernate.impl.SessionImpl  - automatically flushing sessi
on
2297 [main] DEBUG org.hibernate.jdbc.JDBCContext  - before transaction completio
n
2297 [main] DEBUG org.hibernate.impl.SessionImpl  - before transaction completio
n
2297 [main] DEBUG org.hibernate.transaction.JDBCTransaction  - committed JDBC Co
nnection
2297 [main] DEBUG org.hibernate.jdbc.JDBCContext  - after transaction completion
As can be seen no delete query was fired. I then tweaked the code.
Entity entity = new Entity();
entity.setId(2);
//entity.setData("Temp Object"); 
Earlier the id field was null and so Hibernate was unable to perform the delete. Here I set the right id and executed the code:
781  [main] DEBUG org.hibernate.event.def.DefaultDeleteEventListener  - entity 
was not persistent in delete processing
814  [main] DEBUG org.hibernate.event.def.AbstractFlushingEventListener  - Flush
ed: 0 insertions, 0 updates, 1 deletions to 1 objects
818  [main] DEBUG org.hibernate.persister.entity.AbstractEntityPersister  - Dele
ting entity: [com.model.Entity#2]
    delete 
    from
        ENTITY 
    where
        id=?
As seen above Hibernate treated the new object like a transient object and scheduled it for deletion aftre re-attaching it to a session.
public static void deleteProxy() {
    Session session1 = sessionFactory.openSession();
    Entity entity = (Entity) session1.load(Entity.class, 2); 
    Transaction transaction = session1.beginTransaction();
    session1.delete(entity);
    transaction.commit();
    session1.close();
}
The logs now showed a different result:
2282 [main] DEBUG org.hibernate.impl.SessionImpl  - opened session at timestamp:
 13537451031
2313 [main] DEBUG org.hibernate.event.def.DefaultLoadEventListener  - loading en
tity: [com.model.Entity#2]
2313 [main] DEBUG org.hibernate.event.def.DefaultLoadEventListener  - creating n
ew proxy for entity
...
2329 [main] DEBUG org.hibernate.jdbc.JDBCContext  - after transaction begin
2329 [main] DEBUG org.hibernate.impl.SessionImpl  - initializing proxy: [com.mod
el.Entity#2]
...
2329 [main] DEBUG org.hibernate.persister.entity.AbstractEntityPersister  - Fetc
hing entity: [com.model.Entity#2]
2344 [main] DEBUG org.hibernate.SQL  - 
    select
        entity0_.id as id0_0_,
        entity0_.DATA as DATA0_0_ 
    from
        Entity entity0_ 
    where
        entity0_.id=?
2391 [main] DEBUG org.hibernate.loader.Loader  - done entity load
...
2391 [main] DEBUG org.hibernate.event.def.DefaultDeleteEventListener  - deleting
 a persistent instance
2391 [main] DEBUG org.hibernate.event.def.DefaultDeleteEventListener  - deleting
 [com.model.Entity#2]
2422 [main] DEBUG org.hibernate.SQL  - 
    delete 
    from
        Entity 
    where
        id=?
As can be seen both a delete and a select query was fired. But I was working with a proxy. So why the select query ?
This is important: An object can be deleted only if it exists in the session's persistence context. When we made the delete call, Hibernate did not find the object in the persistence context (Remember proxies will not be there in it.) So Hibernate had to first fetch the object and then delete it.

No comments:

Post a Comment