Continuing from the last post, I shall now make the Person Chocolate relation bidirectional. This means that chocolate will also hold a collection of its fans. Instead of using a set here, I decided to use a bag. The updated java files are as below:
Chocolate.hbm.xml
People.hbm.xml
public class People { private Integer id; private String name; private Set<Chocolate> favouriteChocolates = new HashSet<Chocolate>(); public synchronized void addChocolateFanRelation(final Chocolate chocolate) { chocolate.addNewFanToChocolate(this); this.getFavouriteChocolates().add(chocolate); } private synchronized void removeLink(final Chocolate chocolate) { this.getFavouriteChocolates().remove(chocolate); chocolate.removeFanFromChocolate(this); } public synchronized void removeFanChocolateRelation(final Chocolate chocolate) { this.removeLink(chocolate); } @Override public int hashCode() { int hash = this.getName().hashCode(); hash = hash * 17 + this.getName().hashCode(); return hash; } @Override public boolean equals(Object obj) { boolean isEqual = false; if (obj instanceof People) { People people = (People) obj; isEqual = people.getName().equals(this.getName()); } return isEqual; } //setter getter methods }As can be seen the code to delete and add is more complex than before. The code for Chocolate class is as below
public class Chocolate { private Integer id; private String name; private String brand; private Collection<People> fans = new ArrayList<People>(); protected synchronized void addNewFanToChocolate(People fan) { boolean alreadyPresent = false; Collection<People> fanCollection = this.getFans(); for (Iterator<People> fanIterator = fanCollection.iterator();
fanIterator.hasNext();) {
People people= fanIterator.next();
if (people.equals(fan) ) {
alreadyPresent = true;
break;
}
}
if(!alreadyPresent) {
fanCollection.add(fan);
}
}
protected synchronized void removeFanFromChocolate(People fan) {
Collection<People> fanCollection = this.getFans();
for (Iterator<People> fanIterator = fanCollection.iterator();
fanIterator.hasNext();) {
People people= fanIterator.next();
if (people.equals(fan) ) {
fanIterator.remove();
break;
}
}
}
@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;
}
//setter and getter methods
}
The mapping files are as below:Chocolate.hbm.xml
<?xml version="1.0"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"> <hibernate-mapping package="com.association.many_to_many.bidir"> <class name="Chocolate" table="CHOCOLATE"> <id name="id" type="integer"> <column name="ID" /> <generator class="identity" /> </id> <property name="name" type="string"> <column name="NAME" /> </property> <property name="brand" type="string"> <column name="BRAND" /> </property> <bag name="fans" table="CHOCOLATE_FAN" inverse="true"> <key column="CHOCOLATE_ID" /> <many-to-many class="People" column="FAN_ID" /> </bag> </class> </hibernate-mapping>The collection is defined with inverse attribute set to true. So the People entity is the owner of the association. The mapping for People is:
People.hbm.xml
<?xml version="1.0"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"> <hibernate-mapping package="com.association.many_to_many.bidir"> <class name="People" table="PEOPLE"> <id name="id" type="integer"> <column name="ID" /> <generator class="identity" /> </id> <property name="name" type="string"> <column name="NAME" /> </property> <set name="favouriteChocolates" table="CHOCOLATE_FAN" cascade="save-update"> <key column="FAN_ID" foreign-key="CHOCOLATE_FAN_FK2"/> <many-to-many class="Chocolate" column="CHOCOLATE_ID" foreign-key="CHOCOLATE_FAN_FK1"/> </set> </class> </hibernate-mapping>As can be seen, the only change here is the cascade setting. The tables created here are same as the last post. I tried to access the records present in the database
static void testLoad() { Session session = sessionFactory.openSession(); Chocolate chocolate1 = (Chocolate) session.get(Chocolate.class, 1); System.out.println("Chocolate " + chocolate1.getName() + " is from brand " + chocolate1.getBrand()); System.out.println("Number of Fans: " + chocolate1.getFans().size()); if (0 != chocolate1.getFans().size()) { for (People people : chocolate1.getFans()) { System.out.println("Fan is " + people.getId() + " ,Name: " + people.getName()); } } Chocolate chocolate2 = (Chocolate) session.get(Chocolate.class, 2); System.out.println("Chocolate " + chocolate2.getName() + " is from brand " + chocolate2.getBrand()); System.out.println("Number of Fans: " + chocolate2.getFans().size()); }The output of above code is:
Chocolate Eclairs is from brand Cadburys Number of Fans: 2 Fan is 1 ,Name: Naina Fan is 2 ,Name: Naresh Chocolate Melody is from brand Parles Number of Fans: 0The select query that used to retrieve the chocolates is :
select
chocolate0_.ID as ID2_0_,
chocolate0_.NAME as NAME2_0_,
chocolate0_.BRAND as BRAND2_0_
from
CHOCOLATE chocolate0_
where
chocolate0_.ID=?
To display the names of the fans the records were fetched using a single query:select fans0_.CHOCOLATE_ID as CHOCOLATE2_1_, fans0_.FAN_ID as FAN1_1_, people1_.ID as ID0_0_, people1_.NAME as NAME0_0_ from CHOCOLATE_FAN fans0_ left outer join PEOPLE people1_ on fans0_.FAN_ID=people1_.ID where fans0_.CHOCOLATE_ID=?As can be seen a join was needed between PEOPLE table and our join table to get all the chocolate fans. Similar thing happens when we navigate from the direction of People:
static void testLoadViaPeople() { Session session = sessionFactory.openSession(); People people = (People) session.get(People.class, 1); System.out.println("Chocolate " + people.getName()); System.out.println("Number of Fans: " + people.getFavouriteChocolates().size()); session.close(); }The queries generated are:
2313 [main] DEBUG org.hibernate.SQL -
select
people0_.ID as ID0_0_,
people0_.NAME as NAME0_0_
from
PEOPLE people0_
where
people0_.ID=?
2375 [main] DEBUG org.hibernate.SQL -
select
favouritec0_.FAN_ID as FAN1_1_,
favouritec0_.CHOCOLATE_ID as CHOCOLATE2_1_,
chocolate1_.ID as ID2_0_,
chocolate1_.NAME as NAME2_0_,
chocolate1_.BRAND as BRAND2_0_
from
CHOCOLATE_FAN favouritec0_
left outer join
CHOCOLATE chocolate1_
on favouritec0_.CHOCOLATE_ID=chocolate1_.ID
where
favouritec0_.FAN_ID=?
I tried the above example with a Set instead of the bag option and it worked just as fine.
No comments:
Post a Comment