July 28, 2014
Hot Topics:
RSS RSS feed Download our iPhone app

Hibernate Basics

  • October 28, 2005
  • By Patrick Peak and Nick Heudecker
  • Send Email »
  • More Articles »

Hibernate IDs and Generators

The id element describes the primary key for the persistent class as well as how the key value is generated. Each persistent class must have an id element declaring the primary key for the relational table. Let's look at the id element:

<id name="id"column="uid"type="long"unsaved-value="null">
<generator class="native"/>
</id>

The name attribute defines the property in your persistent class that will be used to store the primary key value. The id element implies that the Event class has a property also named id:

public Long getId(){
return this.id;
}
public void setId(Long id){
this.id =id;
}

If the column for the primary key has a different name than your object property, the column attribute is used. For our example's purposes, this column name is uid . The values of the type and unsaved-value attributes depend on the generator used.

The generator creates the primary key value for the persistent class. Hibernate provides multiple generator implementations that use various methods to create primary key values. Some implementations increment a value stored in a shared database table, whereas others create hexadecimal strings. Another generator, called assigned , lets you generate and assign the object ID. The assigned generator allows applications to reuse legacy code, such as the UUID generator from an EJB application. A recent introduction is the select generator, which retrieves the primary key value by selecting a value from a database trigger. The generator type you choose determines its behavior based on the underlying database.

You've used the native generator class in mapping definitions. native generators provide portability for mapping documents since the framework can determine the generator method supported by the database. Generators using the native class will use identity or sequence columns depending on available database support. If neither method is supported, the native generator falls back to a high/low generator method to create unique primary key values. Databases supporting identity columns include Sybase, MySQL, Microsoft SQL Server, and IBM DB2. Oracle, PostgreSQL, and SAP DB support sequence columns.

The native generator returns a short, integer, or long value. You've set the type attribute to long, and the id property in the Event object has a type of java.lang.Long. The value of the type attribute and the property type in the object must be the same.

The unsaved-value attribute describes the value of the id property for transient instances of this class. The unsaved-value attribute affects how objects are stored. We'll discuss the impact of this attribute later in the article.

Hibernate Properties

Property elements for the Event object are similar to the id element:

<property name="name"type="string"length="100"/>
<property name="startDate"column="start_date"type="date"/>
<property name="duration"type="integer"/>

Each property element corresponds to a property in the Event object. The name attribute contains the property name, whereas the type attribute specifies the property object type. The column used to store the property value defaults to the property name. The column attribute overrides this default behavior, as shown in the startDate property.

If the type attribute is omitted, Hibernate determines the type using runtime reflection. In certain cases, you must provide the property type, since reflection may not be able to determine the desired type (such as differentiating between the Hibernate DATE and TIMESTAMP types). Valid property types include the Hibernate basic types, such as integer, string, and timestamp, as well as the corresponding Java objects and primitives. However, you aren't limited to basic data types.

The property element may also contain the name of a serializable Java class or a user-defined type. You create a new user-defined type by implementing either the org.hibernate.UserType or org.hibernate. CompositeUserType interface. The fully qualified class name of the user type or the serializable Java class is used as the property type value.

Hibernate Many-to-one Element

The many-to-one element defines the association to the Location class. You can also refer to this association as one-to-one-why can we call this association a many-to-one instead? Hibernate classifies one-to-one associations as two objects sharing the same primary key. One-to-one associations aren't often used with Hibernate, so we won't cover them in detail. Many-to-one associations use foreign keys to maintain the association between two persistent classes. Let's examine many-to-one associations using the association shown in figure 2.

From this figure, you can deduce that many Event instances are associated with a single Location instance. Although the figure doesn't display it, this association is unidirectional, meaning you can navigate

Figure 2. Association between Location and Event

from the Event instance to the Location but not from the Location to the Event instance. At this point, it's worthwhile to present the mapping file for the Location class, shown in listing 4.

Listing 4. Location.hbm.xml

<?xml version="1.0"?>
<hibernate-mapping package="com.manning.hq.ch03">
<class name="Location"table="locations">
<id name="id"column="uid"type="long">
<generator class="native"/>
</id>
<property name="name"type="string"/>
<property name="address"type="string"/>
</class>
</hibernate-mapping>

The mapping for the Location class is similar to the Event mapping, although it doesn't have as many properties and lacks associations to other persistent objects. The association from Event to Location is a simple object reference.

For the Event mapping, the many-to-one element defines object references between persistent objects. Mapping a many-to-one association is straightforward:

   <many-to-one name="location"column="location_id"class="Location"/>

The name attribute gives the name of the property in the object, and the optional column attribute specifies the column used to store the foreign key to the locations table. If you don't give a column attribute, the name attribute is used as the column name. The class attribute names the associated persistent class. Remember that you don't need to give the fully qualified name of the Location class if it's in the package defined in the hibernate-mapping element.

A common question from developers new to Hibernate is how to make a many-to-one relationship lazy, meaning that the associated object won't be retrieved when the parent object is retrieved. The solution is to use proxied objects.

Object Proxies

An object proxy is just a way to avoid retrieving an object until you need it. Hibernate 2 does not proxy objects by default. However, experience has shown that using object proxies is preferred, so this is the default in Hibernate 3.

Object proxies can be defined in one of two ways. First, you can add a proxy attribute to the class element. You can either specify a different class or use the persistent class as the proxy. For example:

   <class name="Location"
proxy="com.manning.hq.ch03.Location"...>...
</class>

The second method is to use the lazy attribute. Setting lazy="true"is a shorthand way of defining the persistent class as the proxy. Let's assume the Location class is defined as lazy:

   <class name="Location"lazy="true"...>...</class>

The lazy attribute is true by default in Hibernate 3. An easy way to disable all proxies, including lazy collections, is to set the default-lazy attribute to true in the hibernate-mapping element for a given mapping file. Let's look at an example of using a proxied Location instance:

   Session session =factory.openSession();
Event ev =(Event)session.load(Event.class,myEventId);
Location loc =ev.getLocation();
String name =loc.getName();
session.close();

The returned Location instance is a proxy. Hibernate populates the Location instance when getName()is called.

You'll be dealing with a proxy of Location generated by CGLIB until you call an instance method. (CGLIB is a code generation library used by Hibernate. You can find out more about it at http://cglib.sourceforge.net/.) What happens when you retrieve the Event instance from the database? All the properties for the Event are retrieved, along with the ID of the associated Location instance. The generated SQL looks something like this:

    select event0_.id as id0_,event0_.name as name0_,
event0_.location_id as location_id0_from events event0_
where event0_.id=?

When you call loc.getName(), the following generated SQL is executed:

    select location0_.id as id0_as id0_,location0_.name as name0_
from locations location0_where location0_.id=?

If you've guessed that you can call loc.getId()without invoking a call to the database, you're correct. The proxied object already contains the ID value, so it can be safely accessed without retrieving the full object from the database.

Next, we'll look at collections of persistent objects. Like proxies, collections can also be lazily populated.

Collections

The mapping file defines the collections for Speaker’s and Attendee’s. Since the two collections are essentially the same, we're just going to look at the Speaker collection here. The collections are defined as sets, meaning Hibernate manages the collections with the same semantics as a java.util.Set:

    <set name="speakers">
<key column="event_id"/>
<one-to-many class="Speaker"/>
</set>

This definition declares that the Event class has a property named speakers, and that it's a Set containing instances of the Speaker class. The Event class has the corresponding property:

    public class Event {
private Set speakers;
...
public void setSpeakers(Set speakers){
This.speakers =speakers;
}

public Set getSpeakers(){
return this.speakers;
}
...
}

The key element defines the foreign key from the collection table to the parent table. In this case, the speakers table has an event_id column referring to the id column in the events table. The one-to-many element defines the association to the Speaker class.

We've only touched on persisting collections with Hibernate. In addition to Sets, Hibernate also supports persistent Maps and Lists, as well as arrays of objects and primitive values.

ORGANIZING YOUR MAPPING FILES

Let's take a quick break from discussing Hibernate's persistence features and discuss a matter of practice: the location of mapping files. After you create mapping files for each persistent class, where should they be stored so the application can access them? Ideally, mapping files should be stored in the same JAR file as the classes they describe. Suppose the class file for the Event object is stored in the com/manning/hq directory and therefore in the com.manning.hq package. The Event.hbm.xml file should also be stored in the com/manning/hq directory inside the JAR archive.


Tags: Object relational mapping, Java Persistence



Page 2 of 5



Comment and Contribute

 


(Maximum characters: 1200). You have characters left.

 

 


Sitemap | Contact Us

Rocket Fuel