Hibernate, Entities and Database Generation"

From Documentation
m
m
Line 3: Line 3:
 
__TOC__
 
__TOC__
  
Hibernate persists Objects to the database but to do this we need two things, a database schema and a set of mapped classes. In the previous section we explored the Hibernate configuration file and found the following lines:
+
Hibernate persists Objects to the database. To perform this task we need two things, a database schema and a set of mapped classes. In the previous section we explored the Hibernate configuration file and highlighted the following lines:
  
 
<source lang="xml">
 
<source lang="xml">
Line 15: Line 15:
  
 
One of the most important properties in this XML file is “hibernate.hbm2ddl.auto” set as “create-drop”. When set to create the option will create exports the schema DDL to the database when Hibernate’s SessionFactory is created. This is very useful when developing a data driven application as it eliminates the need to manually update SQL scripts when your schema needs to change. However, this setting is not recommended for production usage.
 
One of the most important properties in this XML file is “hibernate.hbm2ddl.auto” set as “create-drop”. When set to create the option will create exports the schema DDL to the database when Hibernate’s SessionFactory is created. This is very useful when developing a data driven application as it eliminates the need to manually update SQL scripts when your schema needs to change. However, this setting is not recommended for production usage.
 +
 +
'''NOTE''': As the database schema is generated and dropped at the beginning and end of every session this means that the data is not persisted past the end of the application. By changing this to update the data will be persisted across multiple runs.
  
 
The other properties enable the mapping of Java classes to Database tables. In general, this mapping is declared in two ways:
 
The other properties enable the mapping of Java classes to Database tables. In general, this mapping is declared in two ways:
  
*By giving the class name using the attribute class
+
*By providing the class name using the attribute <mp>class</mp>
 
*By providing a URI to an XML resource which describes the mapping
 
*By providing a URI to an XML resource which describes the mapping
  
Mapping by XML or annotations achieve the same task and generally the method of description depends on the developer. Some developers prefer XML, some prefer annotations.  In this case we chose to use annotations.
+
Mapping by XML or annotation achieve the same goal and the implementation method depends on developer preference. Some developers prefer XML, some prefer annotations.  In this case we chose to use annotations.
  
 
===Using Hibernate Annotations===
 
===Using Hibernate Annotations===
  
Annotations in Hibernate are placed on the class declaration when instructing Hibernate that the class is an Entity. Then developers have a choice, annotations can be places on field declarations or on the getter of the property.
+
When instructing Hibernate that the class is an Entity which should be persisted the annotation is placed above the class declaration. For property declarations annotations can be placed directly above the field or on the getter of the property.
  
There are varying opinions on which is better and why however, in this case we have chosen to place the annotation on the field value as it is clearer for the purposes of this chapter. Having established where annotations are placed let’s investigate what is actually placed using a class as an example.
+
There are varying opinions on which is better and why, however, in this case we have chosen to place the annotation on the field value as it is clearer for demonstration purposes. The following is the <mp>Product</mp> class which has been annotated.
  
 
<source lang="java">
 
<source lang="java">
Line 52: Line 54:
 
</source>
 
</source>
  
The above code demonstrates how the Product class was annotated to allow persistence. Taking the annotations one at a time we will explore what they do.
+
The above code demonstrates how the <mp>Product</mp> class was annotated to allow persistence. Taking the annotations one at a time we will explore what they do.
  
 
====@Entity====
 
====@Entity====
Line 60: Line 62:
 
====@Table(name="products")====
 
====@Table(name="products")====
  
The table entity is set at the class level and enables us to define the table, catalog and schema names of the entity mappings. If names are not specified then the default values are used, however, in our case product is an SQL reserved word therefore we cannot leave it as default hence we set the name as products in this case.
+
The table entity is set at the class level and enables us to define the table, catalog and schema names of the entity mappings. If names are not specified then the default values are used, however, in our case Product is an SQL reserved word therefore we change the table name to products.
  
 
====@Id====
 
====@Id====
  
We need to let Hibernate know which field of ours id the ID, in this case this is easily achieved by applying the annotation @Id.
+
We need to let Hibernate know which field of ours id the ID, this is easily achieved by applying the annotation @Id.
  
  
 
====@GeneratedValue(strategy=GenerationType.AUTO)====
 
====@GeneratedValue(strategy=GenerationType.AUTO)====
  
Along with the annotation for the @Id, if it is auto-incremented by the database we also need to inform Hibernate. In this case we let Hibernate know by specifying the @GeneratedValue and setting the strategy to GenerationType AUTO.
+
Along with the annotation, @Id, we also need to inform Hibernate that it is auto-incremented by the database. We let Hibernate know using the @GeneratedValue annotation and setting the strategy to GenerationType AUTO.
  
 
====@Column(name="productname")====
 
====@Column(name="productname")====
  
The next annotation refers to the definition of a column. Under normal circumstances we do not need to provide a name however, in this case without specifying the name of the column it would default to “name.Just as “product”, “name” is also an SQL reserved keyword therefore we need to specify a better name for the column.
+
The next annotation refers to the definition of a column. Under normal circumstances we do not need to provide a name however, in this case without specifying the name of the column it would default to "name." Just as "product", "name" is also an SQL reserved keyword hence we specify a valid column name, "productname".
  
  
 
====@Temporal(TemporalType.TIMESTAMP)====
 
====@Temporal(TemporalType.TIMESTAMP)====
  
Java APIs do not define the temporal precision of time. When placing data into persistent storage we would like to describe the expected prevision. In this case we use the Temporal attribute to specify it. Types include DATE, TIME and TIMESTAMP.
+
Java APIs do not define the temporal precision of time. When placing data into persistent storage we would like to describe the expected precision. To do this we use the Temporal attribute. Types include DATE, TIME and TIMESTAMP.
 +
 
  
These attributes which we have explored are also used throughout the application in the other beans. There is only one exception to this present in Order.java which explores the description of a linking table using Hibernate annotations.  
+
The rest of the classes in our example use the same annotation strategies. There is only one exception present in '''Order.java''' which describes the relationship between an <mp>Order</mp> and its <mp>OrderItems</mp>.  
  
  
===Creating the linking table===
+
===Creating the Relationship - Linking Table===
  
An <mp>Order</mp> has a one-to-many relationship with <mp>OrderItems</mp>, to map this relationship in the database we need to introduce a linking table name <mp>OrderedItems</mp>. This relationship is shown below:
+
An <mp>Order</mp> has a one-to-many relationship with <mp>OrderItems</mp>, to map this relationship we are required to introduce a linking table named <mp>OrderedItems</mp>. This relationship is shown below:
  
 
[[File:ZKEss_linking_table.png]]
 
[[File:ZKEss_linking_table.png]]
  
In order for Hibernate to generate the database schema and map the relationship correctly we need to tell it about this relationship. To do this we use two annotations:
+
In order for Hibernate to generate the database schema and map the relationship correctly we need to describe it. To do this we use two annotations:
  
 
*@OneToMany
 
*@OneToMany
 
*@JoinTable
 
*@JoinTable
  
Let’s take a look at the relative code.
+
Let’s explore the relative code.
  
 
<source lang="java">
 
<source lang="java">
Line 108: Line 111:
  
  
The “name” sets the table name that Hibernate (in this case) will create. If you are not using Hibernate to create the schema as in this tutorial then it refers to the table name. The “@joinColumn” in this case takes the “name” and “referencedColumnName” which are the name of the column in the table OrderedItems and the name of the referenced column within the entity.  
+
The "name" attribute tells Hibernate the table name which we would like to use or in our case create.  
 +
 
 +
The "joinColumns" attribute requires the foreign key columns of the join table which reference the primary table of the entity owning the association, in this case the order id. On the other hand the "inverseJoinColumns" attribute requires the foreign key columns of the join table which reference the primary table of the entity that does not own the association, in this case the OrderItem’s id.
  
“joinColumns” requires the foreign key columns of the join table which reference the primary table of the entity owning the association, in this case the order id. On the other hand “inverseJoinColumns” requires the foreign key columns of the join table which reference the primary table of the entity that does not own the association, in this case the OrderItem’s id.
+
We provide both attributes a "@joinColumn" annotation requires the '''"name"''' and '''"referencedColumnName"''' which are the name of the column in the table OrderedItems and the name of the referenced column within the entity respectively.  
  
To make it easier, the Order owns the association (ie. Owns the Order items) so its key is passed to “joinColumns” and OrderItem does not own the association so it is passed to “inverseJoinColumns.
+
The <mp>Order</mp> owns the association (ie. Owns the Order items) so its key is passed to "joinColumns" and <mp>OrderItem</mp> does not own the association so its information is passed to "inverseJoinColumns."
  
  
 
===Lazy Loading===
 
===Lazy Loading===
  
There is one last thing to consider; when the object Order is loaded we will also want to load its OrderItems as they will be accessed at the same time. The problem is Hibernate will lazily load collections which are joined. This means that when the Order object is loaded then the its OrderItems aren’t.
+
There is one last thing to consider; when an <mp>Order</mp> object is loaded we want to load its <mp>OrderItems</mp> at the same time. Hibernate only loads the first object level which can lead to exceptions such as a LazyLoadException when we access the item list and it has not been initialized. Meaning when the Order object is loaded then the its OrderItems aren’t.
  
In this case Hibernate only loads the first object level which can lead to exceptions such as a LazyLoadException when we access the item list and it has not been initialized. In this case it is easy to fix by making use of the @LazyCollection annotation and setting the option to FALSE:
+
In this case it is easy to fix by making use of the @LazyCollection annotation and setting the option to FALSE:
  
 
<source lang="java">
 
<source lang="java">
Line 125: Line 130:
 
</source>
 
</source>
  
This will ensure that when an Order is loaded its OrderItems are too. When designing larger systems we will obviously have to take into account how much data should be loaded and whether we should follow lazy loading practices or not. For the purposes of this chapter lazy loading is not required.
+
This will ensure that when an <mp>Order</mp> is loaded its <mp>OrderItems</mp> are too. When designing larger systems we have to take into account how much data should be loaded and whether we should follow lazy loading practices or not. For the purposes of this chapter lazy loading is not required.
 
 
The final item to finishing working with your Hibernate application is to introduce Session management and how we implemented the DAOs to use Hibernate.
 
  
 +
The final section introduces Hibernate Session management and how we implemented the DAOs.
  
  
 
{{ZKEssentialsPageFooter}}
 
{{ZKEssentialsPageFooter}}

Revision as of 11:18, 9 November 2010

Stop.png This article is out of date, please refer to http://books.zkoss.org/zkessentials-book/master/ for more up to date information.


Hibernate persists Objects to the database. To perform this task we need two things, a database schema and a set of mapped classes. In the previous section we explored the Hibernate configuration file and highlighted the following lines:

<property name="hibernate.hbm2ddl.auto">create-drop</property>

<mapping class="demo.model.bean.Order"/>
<mapping class="demo.model.bean.OrderItem"/>
<mapping class="demo.model.bean.User"/>
<mapping class="demo.model.bean.Product"/>

One of the most important properties in this XML file is “hibernate.hbm2ddl.auto” set as “create-drop”. When set to create the option will create exports the schema DDL to the database when Hibernate’s SessionFactory is created. This is very useful when developing a data driven application as it eliminates the need to manually update SQL scripts when your schema needs to change. However, this setting is not recommended for production usage.

NOTE: As the database schema is generated and dropped at the beginning and end of every session this means that the data is not persisted past the end of the application. By changing this to update the data will be persisted across multiple runs.

The other properties enable the mapping of Java classes to Database tables. In general, this mapping is declared in two ways:

  • By providing the class name using the attribute class
  • By providing a URI to an XML resource which describes the mapping

Mapping by XML or annotation achieve the same goal and the implementation method depends on developer preference. Some developers prefer XML, some prefer annotations. In this case we chose to use annotations.

Using Hibernate Annotations

When instructing Hibernate that the class is an Entity which should be persisted the annotation is placed above the class declaration. For property declarations annotations can be placed directly above the field or on the getter of the property.

There are varying opinions on which is better and why, however, in this case we have chosen to place the annotation on the field value as it is clearer for demonstration purposes. The following is the Product class which has been annotated.

@Entity
@Table(name="products")
public class Product {
	
	@Id
        @GeneratedValue(strategy=GenerationType.AUTO)
	private long id;

        @Column(name="productname")
	private String name;

        @Temporal(TemporalType.TIMESTAMP)
	private Date createDate;
	private float price;
	private int quantity;
	private boolean available; 
	private String imgPath;

	
}

The above code demonstrates how the Product class was annotated to allow persistence. Taking the annotations one at a time we will explore what they do.

@Entity

An entity is a lightweight persistence domain objects representing a table in a database. In this case we let Hibernate know that the class Product is an entity. This is required for classes you would like to persist to the database.

@Table(name="products")

The table entity is set at the class level and enables us to define the table, catalog and schema names of the entity mappings. If names are not specified then the default values are used, however, in our case Product is an SQL reserved word therefore we change the table name to products.

@Id

We need to let Hibernate know which field of ours id the ID, this is easily achieved by applying the annotation @Id.


@GeneratedValue(strategy=GenerationType.AUTO)

Along with the annotation, @Id, we also need to inform Hibernate that it is auto-incremented by the database. We let Hibernate know using the @GeneratedValue annotation and setting the strategy to GenerationType AUTO.

@Column(name="productname")

The next annotation refers to the definition of a column. Under normal circumstances we do not need to provide a name however, in this case without specifying the name of the column it would default to "name." Just as "product", "name" is also an SQL reserved keyword hence we specify a valid column name, "productname".


@Temporal(TemporalType.TIMESTAMP)

Java APIs do not define the temporal precision of time. When placing data into persistent storage we would like to describe the expected precision. To do this we use the Temporal attribute. Types include DATE, TIME and TIMESTAMP.


The rest of the classes in our example use the same annotation strategies. There is only one exception present in Order.java which describes the relationship between an Order and its OrderItems.


Creating the Relationship - Linking Table

An Order has a one-to-many relationship with OrderItems, to map this relationship we are required to introduce a linking table named OrderedItems. This relationship is shown below:

ZKEss linking table.png

In order for Hibernate to generate the database schema and map the relationship correctly we need to describe it. To do this we use two annotations:

  • @OneToMany
  • @JoinTable

Let’s explore the relative code.

@OneToMany
@JoinTable(
    name="OrderedItems",
    joinColumns=@JoinColumn(name="orderid"),
    inverseJoinColumns=@JoinColumn(name="orderitemid")
)
@LazyCollection(value=LazyCollectionOption.FALSE)
private List<OrderItem> items = new ArrayList<OrderItem>();


The "name" attribute tells Hibernate the table name which we would like to use or in our case create.

The "joinColumns" attribute requires the foreign key columns of the join table which reference the primary table of the entity owning the association, in this case the order id. On the other hand the "inverseJoinColumns" attribute requires the foreign key columns of the join table which reference the primary table of the entity that does not own the association, in this case the OrderItem’s id.

We provide both attributes a "@joinColumn" annotation requires the "name" and "referencedColumnName" which are the name of the column in the table OrderedItems and the name of the referenced column within the entity respectively.

The Order owns the association (ie. Owns the Order items) so its key is passed to "joinColumns" and OrderItem does not own the association so its information is passed to "inverseJoinColumns."


Lazy Loading

There is one last thing to consider; when an Order object is loaded we want to load its OrderItems at the same time. Hibernate only loads the first object level which can lead to exceptions such as a LazyLoadException when we access the item list and it has not been initialized. Meaning when the Order object is loaded then the its OrderItems aren’t.

In this case it is easy to fix by making use of the @LazyCollection annotation and setting the option to FALSE:

@LazyCollection(value=LazyCollectionOption.FALSE)

This will ensure that when an Order is loaded its OrderItems are too. When designing larger systems we have to take into account how much data should be loaded and whether we should follow lazy loading practices or not. For the purposes of this chapter lazy loading is not required.

The final section introduces Hibernate Session management and how we implemented the DAOs.



Last Update : 2010/11/09

Copyright © Potix Corporation. This article is licensed under GNU Free Documentation License.