Search This Blog

Sunday, 6 November 2011

Deleting from Collections

In the previous examples I created and used collections that represented simple value elements or components. However one thing that I wanted to try is deleting from collections. Removing the value from the collection for a session bound
entity should ensure the deletion of the row from the appropriate database table.
For Collection of <elements>
I am using the same example used in the earlier post. Here I simply wrote a function to load the person object and delete an element from a map, set and a list. The code is as below
static void deleteElements() {
    Session session = sessionFactory.openSession();
    Transaction t = session.beginTransaction();
    //removing an element from the set
    Person person = (Person) session.get(Person.class, 1L);        
    person.getKids().remove("Kid ZZZ");
    t.commit();
        
    t = session.beginTransaction();
    //removing an element from the list
    person.getDegress().remove(0);
    t.commit();
        
    t = session.beginTransaction();
    //removing an element from the map
    person.getDegreeScore().remove("Degree 1");
    t.commit();
}
Based on the logs, I have pulled out lines of interest: Before we proceed to deletion, this is what the Person object looks like before deletion:
13782 [main] DEBUG org.hibernate.pretty.Printer  - com.collection.basic.Person{i
d=1, degreeScore=[52, 82, 71], degress=[Degree 1, Degree 2, Degree 3], kidsAge=[
12, 15], name=Raman, hobbies=[Music, Sleeping, Video Games], kids=[Kid YYY, Kid 
ZZZ]}
Set Removal
6906 [main] DEBUG org.hibernate.loader.Loader  - loading collection: [com.colle
ction.basic.Person.kids#1]
16906 [main] DEBUG org.hibernate.jdbc.AbstractBatcher  - about to open PreparedS
tatement (open PreparedStatements: 0, globally: 0)
16906 [main] DEBUG org.hibernate.SQL  - 
    select
        kids0_.PERSON_ID as PERSON1_0_,
        kids0_.KID as KID0_ 
    from
        PERSON_KIDS kids0_ 
    where
        kids0_.PERSON_ID=?
Hibernate executes a query to fetch the set of kids when I access the kid property of the person entity. The other collections are uninitiated.
17047 [main] DEBUG org.hibernate.pretty.Printer  - com.collection.basic.Person{i
d=1, degreeScore=<uninitialized>, degress=<uninitialized>, kidsAge=<uninitialize
d>, name=Raman, hobbies=<uninitialized>, kids=[Kid YYY]}
...
17047 [main] DEBUG org.hibernate.persister.collection.AbstractCollectionPersiste
r  - Deleting rows of collection: [com.collection.basic.Person.kids#1]
17047 [main] DEBUG org.hibernate.jdbc.AbstractBatcher  - about to open PreparedS
tatement (open PreparedStatements: 0, globally: 0)
17047 [main] DEBUG org.hibernate.SQL  - 
    delete 
    from
        PERSON_KIDS 
    where
        PERSON_ID=? 
        and KID=?
The logs are generated as a part of the deletion. Removal from the set is enough to remove the element from the database table. The logs displays the set, after the element (Kid ZZZ) is removed.

List Removal
The query executed to fetch elements for the List property in the person entity is
284188 [main] DEBUG org.hibernate.SQL  - 
    select
        degress0_.PERSON_ID as PERSON1_0_,
        degress0_.DEGREE as DEGREE0_,
        degress0_.DEGREE_INDEX as DEGREE3_0_ 
    from
        PERSON_DEGREES degress0_ 
    where
        degress0_.PERSON_ID=?
The logs that indicate the deletion are as below (Degree 1 is missing from the list.):
284219 [main] DEBUG org.hibernate.pretty.Printer  - com.collection.basic.Person{
id=1, degreeScore=<uninitialized>, degress=[Degree 2, Degree 3], kidsAge=<uninit
ialized>, name=Raman, hobbies=<uninitialized>, kids=[Kid YYY]}
284219 [main] DEBUG org.hibernate.SQL  - 
    delete 
    from
        PERSON_DEGREES 
    where
        PERSON_ID=? 
        and DEGREE_INDEX=?

Map Removal
Hibernate executed the below query to load the map instance
395469 [main] DEBUG org.hibernate.SQL  - 
    select
        degreescor0_.PERSON_ID as PERSON1_0_,
        degreescor0_.SCORE as SCORE0_,
        degreescor0_.DEGREE as DEGREE0_ 
    from
        PERSON_DEGREE_SCORE degreescor0_ 
    where
        degreescor0_.PERSON_ID=?
The logs indicating the deletion is as follows:
395688 [main] DEBUG org.hibernate.pretty.Printer  - com.collection.basic.Person{
id=1, degreeScore=[82, 71], degress=[Degree 2, Degree 3], kidsAge=, name=Raman, hobbies=, kids=[Kid YYY]}
...
395688 [main] DEBUG org.hibernate.SQL  - 
    delete 
    from
        PERSON_DEGREE_SCORE 
    where
        PERSON_ID=? 
        and DEGREE=?
AS can be seen the degreeScore field now has only 2 entries.

I repeated the same for the Component example and got similar results. To ensure correct deletion and readability of logs I implemented the toString(), hashCode() and equals() method in the Component class. Something I should have done in my earlier post itself :(
@Override
public int hashCode() {
    int hash = this.getName().hashCode();
    hash = hash * 17 + this.getBrand().hashCode();
    return hash;
}
    
@Override
public boolean equals(Object obj) {    
    boolean isEqual = false;
    if (obj instanceof Chocolate) {
        Chocolate chocolate = (Chocolate) obj;
        isEqual = chocolate.getName().equals(this.getName())
            && chocolate.getBrand().equals(this.getBrand());
    }
    return isEqual;
}

@Override
public String toString() {
    return "{Chocolate: [Name: " + this.getName() + "], [Brand: " + this.brand + "]}";
}
Now an initial snapshot of the ChocolateLover Entity:
3000 [main] DEBUG org.hibernate.pretty.Printer  - com.collection.basic.Chocolate
Lover{id=1, name=Robert, chocolateSet=[component[name,brand]{name=Eclairs, brand
=Cadburys}, component[name,brand]{name=Melody, brand=Parle}], chocolateList=[com
ponent[name,brand]{name=Melody, brand=Parle}, component[name,brand]{name=Eclairs
, brand=Cadburys}], chocolateMap=[component[name,brand]{name=Melody, brand=Parle
}, component[name,brand]{name=Eclairs, brand=Cadburys}]}
The above logs indicate that Hibernate's Printer class uses its own display techniques (and does not give a damn about my toString() method :(  ) The code for deletion testing is as below:
static void deleteElements() {
    Chocolate chocolateToRemove = new Chocolate();
    chocolateToRemove.setName("Eclairs");
    chocolateToRemovesetBrand("Cadburys");
        
    Session session = sessionFactory.openSession();
    Transaction t = session.beginTransaction();
    //removing an element from the set
    ChocolateLover chocoLover = (ChocolateLover) session.get(ChocolateLover.class, 1);        
    chocoLover.getChocolateSet().remove(chocolateToRemove);
    t.commit();
        
    t = session.beginTransaction();
    //removing an element from the list
    chocoLover.getChocolateList().remove(chocolateToRemove);
    t.commit();
        
    t = session.beginTransaction();
    //removing an element from the map
    chocoLover.getChocolateMap().remove(2);
    t.commit();

}
The above code removes the Eclairs chocolates from each of the collection. The logs provide further details about the deletion on removal of the element from each of the collection.
Removal from Set
The SQL Select query to fetch to set is
7703 [main] DEBUG org.hibernate.SQL  - 
    select
        chocolates0_.CL_ID as CL1_0_,
        chocolates0_.CHOCOLATE_NAME as CHOCOLATE2_0_,
        chocolates0_.CHOCOLATE_BRAND as CHOCOLATE3_0_ 
    from
        CHOCOLATE_SET chocolates0_ 
    where
        chocolates0_.CL_ID=?
The deletion logs indicate the absence of eclairs from the set
36828 [main] DEBUG org.hibernate.pretty.Printer  - com.collection.basic.Chocolat
eLover{id=1, name=Robert, chocolateSet=[component[name,brand]{name=Melody, brand
=Parle}], chocolateList=, chocolateMap=}
36828 [main] DEBUG org.hibernate.SQL  - 
    delete 
    from
        CHOCOLATE_SET 
    where
        CL_ID=? 
        and CHOCOLATE_NAME=? 
        and CHOCOLATE_BRAND=?

Removal from List
The SQL Select query to fetch the list property is
783390 [main] DEBUG org.hibernate.SQL  - 
    select
        chocolatel0_.CL_ID as CL1_0_,
        chocolatel0_.CHOCOLATE_NAME as CHOCOLATE2_0_,
        chocolatel0_.CHOCOLATE_BRAND as CHOCOLATE3_0_,
        chocolatel0_.CHOCOLATE_INDEX as CHOCOLATE4_0_ 
    from
        CHOCOLATE_LIST chocolatel0_ 
    where
        chocolatel0_.CL_ID=?
Similarly the Logs for the deletion is
164625 [main] DEBUG org.hibernate.pretty.Printer  - com.collection.basic.Chocola
teLover{id=1, name=Robert, chocolateSet=[component[name,brand]{name=Melody, bran
d=Parle}], chocolateList=[component[name,brand]{name=Melody, brand=Parle}], chocolateMap=}
83406 [main] DEBUG org.hibernate.SQL  - 
    delete 
    from
        CHOCOLATE_LIST 
    where
        CL_ID=? 
        and CHOCOLATE_INDEX=?

Removal from Map
The select query for map is
135843 [main] DEBUG org.hibernate.SQL  - 
    select
        chocolatem0_.CL_ID as CL1_0_,
        chocolatem0_.CHOCOLATE_NAME as CHOCOLATE2_0_,
        chocolatem0_.CHOCOLATE_BRAND as CHOCOLATE3_0_,
        chocolatem0_.FAVOURITE_RANK as FAVOURITE4_0_ 
    from
        CHOCOLATE_MAP chocolatem0_ 
    where
        chocolatem0_.CL_ID=?
And the logs for deletion indicate the removal from the map and the subsequent delete query that was fired by Hibernate
164625 [main] DEBUG org.hibernate.pretty.Printer  - com.collection.basic.Chocola
teLover{id=1, name=Robert, chocolateSet=[component[name,brand]{name=Melody, bran
d=Parle}], chocolateList=[component[name,brand]{name=Melody, brand=Parle}], choc
olateMap=[component[name,brand]{name=Melody, brand=Parle}]}
164625 [main] DEBUG org.hibernate.SQL  - 
    delete 
    from
        CHOCOLATE_MAP 
    where
        CL_ID=? 
        and FAVOURITE_RANK=?
From the above examples we can conclude, that once the element/component is removed from an associated collection, the corresponding row is deleted from the database.
There is no need to make any explicit delete calls to achieve the same.

No comments:

Post a Comment