AdvJava PG Hibernate Unit V
AdvJava PG Hibernate Unit V
AdvJava PG Hibernate Unit V
From the above figure, Java applications use Hibernate to map Java objects to Tables in relational
database.
It’s a light weight ORM solution and doesn’t even need a application server or container to run
the applications.
Offer loose coupling of Javabeans with the underlying tables though the use of XML as the
medium of communication.
Consumes less resources there by improves the overall performance of the application.
Offers significant amount of flexibility in designing persistence applications.
Typical Hibernate Components
Hibernate commonly uses two XML files for persisting data in Java objects.
One is the user defined XML file that contains all the mapping information.
A standard hibernate.cfg.xml file that contains all the database configuration information
along with the locations of user defined mapping XML in step 1.
return firstName;
this.firstName = firstName;
}
return lastName;
this.lastName = lastNamme;
return ssn;
this.ssn = ssn;
return addressLine1;
this.addressLine1 = addressLine1;
return city;
this.city = city;
return country;
this.country = country;
return state;
}
this.state = state;
<?xml version="1.0"?>
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="hibernate.example1.Customer"
table="CUSTOMERS1"> <id name="ssn">
</id>
</class>
</hibernate-mapping>
This mapping file defines a class element that tells Hibernate to map Customer bean to
CUSTOMERS1 table using the following line
<class name="hibernate.example1.Customer" table="CUSTOMERS1">
Specifies the bean properties to the column names. The only tricky part is the id element. Every
table that we map using the class element must have a primary key column and id element
must be used to map a bean property to the primary key.
Configuring Hibernate
Hibernate uses a class called SessionFactory for persisting and loading data objects to and
from the database. Hibernate uses Configuration class to configure the session factory.
SessionFactory can be configured using XML, Property files and even programmatically.
Associations
Associations basically indicate that one class retains the relationship to another class over an
extended period of time. In a Customer-Address example, an address is associated with a
customer.
Moreover associations can be unidirectional or bidirectional.If the association is unidirectional
from A to B, then A can see changes made to B and not vice-versa.With a bidirectional
association, both A and B can see each others changes. The following figure shows both
unidirectional and bidirectional associations.
One-to-One Association
One-to-Many association
Many-to-One association
Many-to-Many association
Many-to-One Association
Unidirectional Many-to-One/One-to-many Association
The simple example for this association is multiple books belonging to the same publisher. At the same time
if only the Books should be able to see the changes made to the publisher, it becomes unidirectional.
BOOKS PUBLISHERS
BOOK_ID PUB_ID AUTHOR TITLE PUB_ID PUB_NAME
101 123 123
102 123
</id>
</class>
The above definition maps publisherId and publisherName to the respective columns in the
PUBLISHERS table. Now look at the class definition for the Book class.
<class name="hibernate.example4.Book" table="BOOKS4">
</id>
</class>
In the above definition, the many-to-one element tells hibernate to use the PUBLISHERS
primary key as the foreign key in the BOOKS table. The PUB_ID column in BOOKS table will
now have the same value as the PUB_ID column in the PUBLISHERS table.
Bidirectional Many-to-one/One-to-Many
In this case, the publisher should have the knowledge of all the books it published. Therefore,
the publisher class should have a collection property for books as shown below:
public class Publisher {
int publisherId;
String publisherName;
Set books;
books.add(book);
book.setPublisher(this);
In the addBook() utility method. If it is tried to associate a book to a publisher, then it is just to update
the record in the books table to set the publisher using the following update statement.
One-to-One Association
In this association, one object (record in one table) should be associated with one and only one
object (record in another table). For example, a book can only be associated with one publisher.
This association can be implemented in two ways.
i)Using Foreign Key
ii)Using Primary Key
BOOKS PUBLISHERS
BOOK_ID PUB_ID AUTHOR TITLE PUB_ID PUB_NAME
101 123 123
102 123
From the above table, a one-to-one relationship can be obtained from a many-to-one
relationship by eliminating the duplicate foreign key (PUB_ID) in the books table. It is
instructed to hibernate by simply setting the unique attribute to true for the PUB_ID in the
class definition for book as shown below:
</id>
</class>
The class definition for Publisher will remain the same as shown below:
<class name="hibernate.example5.Publisher" table="PUBLISHERS5">
<id name="publisherId" column="PUB_ID">
</id>
</class>
When Hibernate generates the DDL for the tables, it adds a foreign key constraint to the
PUB_ID in the Books table as shown
With the above relationship, if it is tried to add more than one book to the same publisher it
will add the first book and then throws an exception.
Bidirectional Foreign Key Association
Making this association bidirectional is nothing but having the publisher access the book
information. The only difference is that in this case, it has to be just one book. Firstly, we need
to add the book reference in the Publisher class as shown below:
int publisherId;
String publisherName;
Book book;
Secondly, the class definition for the Publisher will look as shown below:
<class name="hibernate.example5.Publisher" table="PUBLISHERS5">
</id>
property-ref="publisher" />
</class>
From the above definition, it is added a one-to-one mapping of the book to the publisher
using the property-ref attribute. This tells Hibernate that the book association in Publisher
is the reverse of publisher association in Book.
<generator class="foreign">
<param name="property">book</param>
</generator>
</id>
</class>
The constraint=true attribute tells hibernate that there is a foreign key constraint on the
primary key of the publisher table.
A special generator named foreign must be used which tells hibernate to use the value of the
primary key on the books table as the primary key value in the publishers table.
</id>
<one-to-one name=”publisher”
class=”hibernate.example5.Publisher”/> </class>
The above tells hibernate to also retrieve the publisher while retrieving the book.
Many-to-Many Association
The classical example for this association is the one between Topics and Subscriptions.
Implementing a many-to-many relationship requires an additional table called the link table.
There is no way you can implement this scenario using two tables. The link table basically
contains the primary keys of both the tables as shown in the following diagram:
int topicid;
String topicName;
Set subscribers;
}
The subscriber class will define a collection of topics objects as shown below:
public class Subscriber{
int sid;
String name;
Set topics;
With unidirectional association, a topic will have the knowledge of all the subscribers and not vice-versa.
In this case, the class definition for Topic class will look as shown below:
<class name="hibernate.example6.Topic" table="TOPICS6">
</id>
<many-to-many column="SUB_ID"
class="hibernate.example6.Subscriber" />
</set>
</class>
From the above definition, the set element tells hibernate to insert TOPIC_ID from TOPICS6 table
and SUB_ID from SUBSCRIBERS6 table into the link table TOPIC_SUB6 when the association is
made.
Following is the class definition for subscriber class. This class will not have the subscribers
property defined as we should not allow subscribers to access topics.
<class name="hibernate.example6.Subscriber" table="SUBSCRIBERS6">
<id name="sid" column="SUB_ID">
</id>
</class>
Bidirectional Many-to-Many association
In this case, to update the class definition of the subscriber it is to include the topics property
as a set element as shown below:
<class name="hibernate.example6.Subscriber"
table="SUBSCRIBERS6"> <id name="sid" column="SUB_ID">
</id>
</set>
</class>
From the above definition, this is simply the reverse of the subscribers property in the Topic
class definition. However, it is to add the inverse=”true” attribute to tell hibernate to
synchronize both the ends of the association .
Polymorphic associations:
Polymorphic association is an association in which a child object is referenced by a parent class
reference. The parent component can be a concrete parent class, or an abstract class or even an
interface. With polymorphic associations following are the two cases we need to look at:
From the above two tables, hibernate will create PRODUCT_ID and
SELLER columns for the inherited properties in each of the table. It’s
important to note that hibernate will not create a table for the Product class
as it is abstract.
The ShoppingCart element should use the element any to tell hibernate
about the two columns as shown below:
<any name="product" meta-type="string" id-
type="int" cascade="save-update"> <meta-
value value="BOOK"
class="hibernate.example7.Book" /> <meta-
value value="COMPUTER"
class="hibernate.example7.Computer" />
<column name="PRODUCT_TYPE" />
</any>
From the above mapping, the any element defined two columns is as
shown below:
<column name="PRODUCT_TYPE" />
package hibernate.example7;
int productId;
String seller;
String isbn;
String author;
String title;
String publisher;
return title;
this.title = title;
return author;
this.author = author;
return isbn;
this.isbn = isbn;
return publisher;
}
this.publisher = publisher;
return productId;
this.productId = productId;
return seller;
this.seller = seller;
package hibernate.example7;
String processor;
int ramSize;
String os;
String type;
this.os = os;
return processor;
this.processor = processor;
return ramSize;
this.ramSize = ramSize;
return type;
this.type = type;
return productId;
this.productId = productId;
}
public String getSeller() {
return seller;
this.seller = seller;
int clientId;
Product product;
return clientId;
this.clientId = clientId;
return product;
this.product = product;
}
The above code represent the JavaBean classes for Product, Book,
ShoppingCart and Computer.
<?xml version="1.0"?>
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
polymorphism="implicit">
</id>
</class>
polymorphism="implicit">
</id>
</class>
<class
name="hibernate.example7.Shopping
Cart" table="SHOPPINGCART7"> <id
name="clientId"
column="PRODUCT_ID">
</id>
cascade="save-update">
<meta-value value="COMPUTER"
class="hibernate.example7.Computer" />
</any>
</class>
</hibernate-mapping>
Notice the class mappings for Book and Computer. They simply map their
respective properties to columns in tables like we did in the very first example.
The only difference is that it is to add polymorphism=”true” attribute to tell
hibernate that their associations are polymorphic in nature. Also note that both
the classes uses the inherited productId as the primary key.
b.setAuthor("James");
b.setTitle("J2EE");
b.setPublisher("Pub Inc");
b.setSeller("JC Inc");
cart.setProduct(b);
session.save(cart);
session.getTransaction().commit();
The above code will insert one record in the books table and one in the
shoppingcart table. Now, we can use the following code to retrieve the
shopping cart which also retrieves the book object.
ShoppingCart c1 =
(ShoppingCart)session.get(ShoppingCart.cl
ass,new Integer(1)); Book b =
(Book)c1.getProduct();
This approach though works well is very seldom used due to its inherent
complexity. Use this technique when require polymorphic association is
not required.
polymorphism="implicit">
</id>
</subclass>
<subclass name="hibernate.example7.Computer"
discriminator-value="COMPUTER">
</subclass>
</class>
From the above definition for the product class, it defined a discriminator
column along with two subclass elements, one for book and other for
computer class. Also note that the subclass elements specified a
discriminator values namely BOOK and COMPUTER for hibernate to
distinguish between the two.
Now, the mapping from ShoppingCart to Product can be implemented as
a one-to-one association as shown below:
</id>
cascade="save-update" />
</class>
From the above, the following two important things are observed:
Hibernate will eliminate the columns for the inherited properties in the
Books and Computers table, and adds a primary key column.
Because of the elimination of the columns in step1, it will create a table
for the abstract class Product with columns for inherited properties.
joined-subclass element as shown below. The mapping is just the same as with
subclass element.
polymorphism="implicit">
</id>
<joined-subclass
name="hibernate.example7
.Book" table="BOOKS9">
<key
column="BOOK_ID" />
</joined-subclass>
<joined-subclass
name="hibernate.example7.Computer
" table="COMPUTERS9"> <key
column="COMP_ID" />
</class>
From the above class mapping for Product, it defined its own properties like
productId and seller and then defined the mappings for its subclasses using the
joined-subclass element. The only difference you’d notice with this element
compared to the subclass element in the previous example is that we specified the
table names highlighted in bold and defined the key column in both the subclass
tables.
Hibernate supports two important classes namely Query and Criteria to query for
objects. Either Query or Criteria class can be used for retrieving objects. In
some cases using Query is more flexible and in some other cases using
Criteria is more flexible.
Case 1: To retrieve all the Book objects from the BOOKS table.
Using Query:
Query query = session.createQuery(“from Book”);
In this case, creating the Query object from the session by specifying the
query string. With the string “from Book”, hibernate will automatically figure out
the table name based on the mappings that defined in the xml and returns all
the Book object populating all the properties with the column data. Behind the
scenes, hibernate will translate the above into the following SQL:
Select bookId, author, publisher from BOOKS;
Using Criteria
Criteria c = session.createCriteria(Book.class);
In this case, Hibernate will return all the Book objects from the BOOKS
table by just specifying the class of the objects to retrieve..
Using Query
String qs= “from Book b where b.author like :author”;
Query q = session.createQuery(qs);
q.setString(“author”,”James”);
In the above query, “:author” is the query parameter. With HQL, all the
parameters must be prefixed with a colon as shown. Based on the type of
data to be passed to the parameter, we can use the set methods defined
by the Query interface. One such method is the setString() method to set
the character data. Likewise, there are several other set methods for
passing dates, numbers etc,. The above query retrieves all the Book
objects that are authored by James.
Query q = session.createQuery(qs);
q.setString(0,”James”);
setString(0,”James”).
setString(1,”Premium Publishing”).
list();
These are all the basic HQL operations that need to know. Using both
Query and Criteria interfaces you can build any complex queries for
retrieving the objects.