Hibernate, Entities and Database Generation"

From Documentation
m
Line 3: Line 3:
 
__TOC__
 
__TOC__
  
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:
+
Hibernate persists Objects to the database. To perform this task we need two things, a database schema and a set of mapped classes are needed. In the previous section, we've explored the Hibernate configuration file and highlighted the following lines:
  
 
<source lang="xml">
 
<source lang="xml">

Revision as of 07:37, 23 June 2011

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 are needed. In the previous section, we've 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 : 2011/06/23

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