DekGenius.com
[ Team LiB ] Previous Section Next Section

8.2 Persistence Approach

As you have seen with all of the other automated persistence systems in this book, Castor and Hibernate both persist component attributes by reading an XML configuration file that defines persistence mapping. Table 8-1 shows the attributes of two business objects we might want to persist to a database.

BEST PRACTICE: Though each framework lets you specify all persistence mapping in a single XML file, you should limit each XML file to describing the mapping of a single class.

Table 8-1. The attributes of two business objects with the mapping type to be used

Class

Attribute

Type

Author

authorID

Long

 

firstName

String

 

lastName

String

 

Publications

List

Book

bookID

Long

 

Author

Author

 

Title

String

Example 8-1 contains the code for the Author class described in Table 8-1.

Example 8-1. A persistent Author class
package book;
   
public class Author {
    private long   authorID;
    private String firstName;
    private String lastName;
    private Set    publications;
   
    public long getAuthorID ( ) {
        return authorID;
    }
   
     public String getFirstName( ) {
        return firstName;
    }
   
    public String getLastName( ) {
        return lastName;
    }
   
    public Set getPublications ( ) {
        return publications;     
    }
   
    public void setAuthorID (long id) [
        authorID  = id;
    }
   
    public void setFirstName(String fn) {
        firstName = fn;
    }
   
    public void setLastName(String ln) {
        lastName = ln;
    }
   
    public void setPublications (Set pubs) {
        publications = pubs;
    }
}

This business class is very simple—nothing but getters and setters to manage the attributes. No persistence code is present. Example 8-2 contains the basic code for the Book class.

Example 8-2. Book value object that contains an Author value object reference
package book;
   
public class Book {
    private Author author;
    private long   bookID
    private String title;
   
    public Author getAuthor ( ) {
        return author;
    }
   
    public long getBookID ( ) {
        return bookID;
    }
   
    public String getTitle ( ) {
        return title;
    }
   
    public void setAuthor (Author auth) {
        author = auth;
    }
   
    public void setBookID (long id) {
        bookID =id;
    }
   
    public String setTitle (String ttl) {
        title = ttl;
    }
}

8.2.1 Castor Field Mapping

The key to Castor and Hibernate persistence is the XML file. Each API has it own definition language for defining the mapping between objects and a table. Example 8-3 shows how Castor maps the business objects to a database.

Example 8-3. Castor XML mapping descriptor
<?xml version="1.0"?>
<!DOCTYPE mapping PUBLIC "-//EXOLAB/Castor Mapping DTD Version 1.0//EN" "http://castor.
exolab.org/mapping.dtd">
   
<mapping>
    <class name="book.Author" identity="authorID" key-generator="MAX">
        <map-to table="AUTHOR"/>
        <field name="authorID" type="long">
            <sql name="AUTHORID"/>
        </field>
        <field name="firstname" type="java.lang.String">
            <sql name="FIRSTNAME"/>
        </field>
        <field name="lastname" type="java.lang.String">
            <sql name="LASTNAME"/>
        </field>
        <field name="publications" type="book.Book" collection="set">
            <sql many-key="authorid"/>
        </field>
    </class>
   
    <class name="book.Book" identity="bookID" key-generator="MAX">
        <map-to table="BOOK"/>
        <field name="bookID" type="long">
            <sql name="BOOKID"/>
        </field>
        <field name="title" type="java.lang.String">
            <sql name="TITLE"/>
        </field>
        <field name="author" type="book.Author">
            <sql name="AUTHORID"/>
        </field>
    </class>
</mapping>

For each class you wish to map, you have a class[2] entry in your XML-descriptor. This tag identifies the following:

[2] The use of the word class makes this XML dialect technically illegal since class is a reserved word in XML.

  • The name of the Java class being mapped.

  • The name of the identity attribute (the attribute that uniquely identifies an instance of the class).

  • The key generation tool to use to generate identity values. Both Castor and Hibernate provide several methods of generating unique values.

BEST PRACTICE: Choose the sequence generation method that best suits your persistence framework of choice.

Castor supports the following key generation algorithms:


HIGH-LOW

This algorithm uses a mechanism similar to the custom sequence generation algorithm described in Chapter 4. It requires a special sequence table whose keys are the names of tables and whose columns are seed values for sequence generation. For more on seed values, look at the sequence generation part of Chapter 4.


IDENTITY

The value generated is based on the value generated by the proprietary identity generation scheme of the underlying database engine. Supported databases include Hypersonic SQL, MS SQL Server, MySQL, and Sybase ASE/ASA.


MAX

The value generated is one greater than the maximum value currently in the database.


SEQUENCE

The value generated comes from the proprietary SEQUENCE concept of Interbase, Oracle, PostgreSQL, and SAP DB.


UUID

This algorithm generates a globally unique value based on the IP address, current system time in milliseconds, and a static counter.

The SEQUENCE and HIGH-LOW algorithms require parameters. You can specify the parameters using the key-generator tag outside the class tag:

<key-generator name="HIGH-LOW">
  <param name="table" value="Sequence"/>
  <param name="key-column" value="name"/>
  <param name="value-column" value="seed"/>
  <param name="grab-size" value="1000000"/>
</key-generator>

BEST PRACTICE: Use the HIGH-LOW key generation algorithm.

Within the <class></class> enclosure is the set of tags that defines the mapping of class attributes to database tables. The first tag in the group is the map-totable tag. As its name suggests, it specifies the name of the database table to which the attributes of this class map.

The rest of the tags define the actual field-to-column mappings. The tag of special interest is the one that defines how an Author relates to Book. Instead of identifying a column in the AUTHOR table, it identifies an attribute in the Book class. Castor then uses the mapping of this column to perform the appropriate joins.

8.2.2 Hibernate Field Mapping

Field mapping in Hibernate is quite similar. Example 8-4 shows the XML descriptor that defines that mapping of the sample classes to a database.

Example 8-4. Hibernate XML mapping descriptor
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD//EN" "http://
hibernate.sourceforge.net/hibernate-mapping-1.1.dtd">
   
<hibernate-mapping >
    <class name="book.Author" table="AUTHOR">
        <id name="authorID" column="AUTHORID" type="long">
            <generator class="vm.long"/>
        </id>
        <property name="firstname" column="FIRSTNAME" type="string"/>
        <property name="lastname" column="LASTNAME" type="string"/>
        <set role="publications" lazy="true">
            <key column="AUTHORID"/>
            <one-to-many class="book.Book"/>
        </set>
    </class>
    <class name="book.Book" table="BOOK">
        <id name="bookID" column="BOOKID" type="long">
            <generator class="vm.long"/>
        </id>
        <property name="title" column="TITLE"/>
    </class>
</hibernate-mapping>

The Hibernate code is similar to the Castor code, yet different in many important ways. Again, Hibernate uses a class tag to define the persistence mapping for a specific Java class. Unlike Castor, Hibernate defines the table mapping as a tag attribute.

Within a class, you identity the ID, properties, and sets of the class. The ID is the primary key field. The id tag contains a generator tag to specify a key generation algorithm to use for automated key generation. This tag identifies a Java class that performs a key generation algorithm. If the algorithm requires parameters, they may be specified in the body of the generator tag as param tags:

<generator class="org.dasein.persist.Sequence">
  <param>sequence</param>
</generator>

The generator class is an implementation of cirrus.hibernate.id.IdentifierGenerator. Hibernate provides the following built-in generators:


assigned

Enables the application to generate its own identifiers.


hilo.hex

This algorithm is the same as hilo.long, except the result is a string of 16 characters.


hilo.long

Generates unique long values using a HIGH-LOW algorithm. This generator should not be used in JTA environments or with user-supplied connections.


native

Generates a unique value based on the identity columns for DB2, MS SQL Server, MySQL, Sybase, and Hypersonic SQL.


seqhilo.long

Generates a unique long value for a named sequence using the HIGH-LOW algorithm.


sequence

Generates a unique value based on the SEQUENCE concept from DB2, Interbase, Oracle, PostgreSQL, and SAP DB.


uuid.hex

Generates a globally unique 32-character string.


uuid.string

Identical to uuid.hex, except it generates a 16-character ASCII string. This algorithm should not be used with PostgreSQL.


vm.hex

Generates unique strings based on hexadecimal digits. This algorithm should not be used in a cluster.


vm.long

Generates unique long values. This algorithm should not be used in a cluster.

BEST PRACTICE: Most persistence platforms offer a variety of sequence generation approaches; it is important to use a sequence generator that will fit your overall high-level architecture for system requirements such as clustering.

Properties are the basic attributes of the class. Sets, on the other hand, represent the one-to-many or many-to-many mappings for the class. Again, our objects map one author to many books. Hibernate captures this relationship through the set tag.

Hibernate supports six different collection tags:

  • <array>

  • <bag>

  • <list>

  • <map>

  • <primitive-array>

  • <set>

For all of these set types except arrays, you can enable lazy-loading through the lazy="true" attribute. Using lazy-loading can greatly increase the speed of your application for operations such as searching. Additional approaches such as caching can also greatly increase the speed of your application. It is worthy to note that most alternative persistence APIs offer some type of built-in object caching that can be turned on or off.

BEST PRACTICE: When choosing a persistence API it is important to fully understand the different mapping types that an API supports. Each persistence system will have its own weaknesses and may not support advanced mapping types such as one-to-many and many-to-one mapping types.

    [ Team LiB ] Previous Section Next Section