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