In this example I created the relation between shelf and book and set the direction of relation from Book to Shelf. i.e. the Book is aware of the shelf. Which is the same case as the db schema. The foreign key is in the Book table and not vice-versa.
This mapping is sufficient for most cases.
However Hibernate also offers the option of making the shelf class aware of the Books placed on it. It is possible to completely manage the life cycle of all Books on a given Shelf right from the shelf class, as we do in the case of components. The changes to the previous example would be in both the entities and the mapping files. To maintain the example of unidirectional relationships, I have removed the reference to shelf from the Book class.
As before we can use cascade settings here to manage the association. The saving of shelf should also save the books on it. This would then be like a parent child relationship.
This can be achieved with the cascade settings.
Also calling a delete on shelf entity would delete the children entities. As books cannot exists if the shelf is removed. But care needs to be taken that the references between shelf and its books is broken from any other rows in the table. In the next example I shall look at working with a bidirectional relationship.
This mapping is sufficient for most cases.
However Hibernate also offers the option of making the shelf class aware of the Books placed on it. It is possible to completely manage the life cycle of all Books on a given Shelf right from the shelf class, as we do in the case of components. The changes to the previous example would be in both the entities and the mapping files. To maintain the example of unidirectional relationships, I have removed the reference to shelf from the Book class.
public class Book { private String name; private Integer id; //setter-getter methods }Shelf.java
public class Shelf { private Integer id; private String code; private Set<Book> books = new HashSet<Book>(); //setter getter methods public void addBook(Book book1) { books.add(book1); } }The addBook() method is a utility method that is used to create a link between the Book and the Shelf entity. The changes to the mapping fields is as below:
Book.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.collection.undirectional1"> <class name="Book" table="BOOK"> <id name="id" type="integer"> <column name="ID" /> <generator class="native" /> </id> <property name="name" type="string"> <column name="Name" length="50" not-null="true" /> </property> </class> </hibernate-mapping>
Shelf.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.collection.undirectional1"> <class name="Shelf" table="SHELF"> <id name="id" type="integer"> <column name="ID" /> <generator class="native" /> </id> <property name="code" type="string"> <column name="CODE" length="50" not-null="true" /> </property> <set name="books"> <!-- THE foreign-key attribute used for generated DDL --> <key column ="SHELF_ID" foreign-key=BOOK_FK_1" not-null="true" /> <one-to-many class="Book" /> <!-- One Shelf has many books --> </set> </class> </hibernate-mapping>The start up logs indicate the same SQL scripts were fired as before:
2875 [main] DEBUG org.hibernate.tool.hbm2ddl.SchemaExport - create table BOOK ( ID integer not null auto_increment, Name varchar(50) not null, SHELF_ID integer not null, primary key (ID) ) 2875 [main] DEBUG org.hibernate.tool.hbm2ddl.SchemaExport - create table SHELF ( ID integer not null auto_increment, CODE varchar(50) not null, primary key (ID) ) 2890 [main] DEBUG org.hibernate.tool.hbm2ddl.SchemaExport - alter table BOOK add index SHELF_FK_1 (SHELF_ID), add constraint BOOK_FK_1 foreign key (SHELF_ID) references SHELF (ID)The code to create a shelf with books is as below:
static void create() { Shelf shelf1 = new Shelf(); shelf1.setCode("SH01"); Book book1 = new Book(); book1.setName("Lord Of The Rings"); Book book2 = new Book(); book2.setName("Simply Fly"); shelf1.addBook(book1); shelf1.addBook(book2); Session session = sessionFactory.openSession(); Transaction t = session.beginTransaction(); session.save(shelf1); session.save(book1); session.save(book2); t.commit(); System.out.println("The Chocolate Lover with name " + shelf1.getCode() + " was created with id " + shelf1.getId()); System.out.println("Book1 saved with id " + book1.getId() + " and Book2 saved with id " + book2.getId()); }The logs indicate that 3 SQL insert statements were executed as before to save the three entities.
3234 [main] DEBUG org.hibernate.SQL - insert into SHELF (CODE) values (?) 3328 [main] DEBUG org.hibernate.SQL - insert into BOOK (Name, SHELF_ID) values (?, ?) ... 3328 [main] DEBUG org.hibernate.SQL - insert into BOOK (Name, SHELF_ID) values (?, ?) ... 3406 [main] DEBUG org.hibernate.SQL - update BOOK set SHELF_ID=? where ID=? 3406 [main] DEBUG org.hibernate.SQL - update BOOK set SHELF_ID=? where ID=?Along with the SQL statements two update queries were also fired to update the foreign-key reference in the Book table.The Shelf _Id column is a not null field. The value in the new row created for Book includes the value. Hence the update queries are of no real point.
As before we can use cascade settings here to manage the association. The saving of shelf should also save the books on it. This would then be like a parent child relationship.
This can be achieved with the cascade settings.
<set name="books" cascade="save-update,delete"> <key column ="SHELF_ID" foreign-key="BOOK_FK_1" not-null="true" /> <one-to-many class="Book" /> </set>The save code would now change to
static void() { Transaction t = session.beginTransaction(); session.save(shelf1); // session.save(book1); // session.save(book2); t.commit(); }
While the save now occurs with just one line of code, the number of fired queries does not change. Update queries are still fired.
Also calling a delete on shelf entity would delete the children entities. As books cannot exists if the shelf is removed. But care needs to be taken that the references between shelf and its books is broken from any other rows in the table. In the next example I shall look at working with a bidirectional relationship.
No comments:
Post a Comment