More Books
Hibernate: A J2EE Developer's Guide
Hibernate: A J2EE™ Developer's Guide
Table of Contents
Copyright
Acknowledgments
About the Author
Preface
Required Skills
Roadmap
Chapter 1. Overview
Why Object/Relational Mapping?
What Is Hibernate?
Comparing JDBC to Hibernate
Hibernate's Mapping System
Other Java/Database Integration Solutions
How to Obtain and Install
Supported Databases
Chapter 2. Getting Oriented
Application Architecture
Mapping Files
Generating Java Source
Application Configuration
Web Application
JSP Interface
Chapter 3. Starting from Java
Java Object Model
Generated Mapping Files
Generated Schema
Working with Artifacts and Owners
Chapter 4. Starting from an Existing Schema
Initial Schema
Using Middlegen
Generated Mapping Files
Generated Java
Working with the Database
Chapter 5. Mapping Files
Basic Structure
Mapping File Reference
Chapter 6. Persistent Objects
Sessions
Objects and Identity
Life-Cycle Methods
Chapter 7. Relationships
Database Relationships
Java Collection Relationships
Java Class Relationships
Any-Based Relationships
Bi-directional Relationships
Chapter 8. Queries
HQL
HQL Reference
Select
From
Where
Group By
Having
Order By
Criteria Queries
Native SQL Queries
Chapter 9. Transactions
Introduction to Transactions
Optimistic and Pessimistic Locking
Chapter 10. Performance
Finding and Solving Problems
Queries
Inserts
Connection Pooling
Caching
Chapter 11. Schema Management
Updating an Existing Schema
Generating Update and Drop Scripts
Chapter 12. Best Practices, Style Guide, Tips and Tricks
Reducing Code with Inversion of Control
Reducing Session Creation Impact with ThreadLocal
Using Hibernate as an EJB BMP Solution
Integrating with Other Technologies
Applications That Use Hibernate
Strategies for Getting Started
Chapter 13. Future Directions
Hibernate 3.0
EJB 3.0
Here and Now
Index
SYMBOL
A
B
C
D
E
F
G
H
I
J
K
L
M
N
O
P
Q
R
S
T
U
V
W
X

Java Class Relationships

The Java class relationships in Hibernate boil down to two main types, subclasses and components.

A subclass refers to an object-oriented programmer's typical view of a class hierarchy. In the object-oriented view, a dog could be modeled as a subclass of mammal. From a database developer's perspective, subclasses are a way for a Java developer to logically group several different types of records that might be stored in a given table.

A component is a way to nest data within a particular class. For example, a Person class might use a nested component to store the person's address. This is simply a Java developer's tool for managing a table with many columns.

TIP

If you are designing an application top-down, you will probably want to use the discriminator column strategy described in subclasses rather than the joined subclass strategy. This is likely to be the first strategy supported by EJB 3.0, but joined subclasses may not be available until EJB 3.1.


Subclasses

Consider an application that wishes to persist objects of the type com.example.Animal, com.example.Cat, and com.example.Bird to a single table (Cat and Bird, of course, extend Animal). Animal records have the properties name and weight. Cat entries have the additional properties color and teeth, and Bird records the additional properties color and wingspan. A column (called a discriminator) is present in the single table used to keep track of all three classes. The Animal, Cat, and Bird records would be tracked in the database as shown in Table 7.3.

Table 7.3. Single Table Subclasses

Id

Discriminator

Name

Weight

Color

Teeth

Wingspan

1

com.example.Animal

Bob

10

null

null

null

2

com.example.Cat

Ashe

8

gray

26

null

3

com.example.Bird

Mika

2

blue

null

10


Because color is common to both com.example.Cat and com.example.Bird, it is not repeated. Note that columns not used by an object are set to nullfor example, com.example.Cat has no wingspan, and therefore that value is set to null. Make sure that the columns used by your subclass do not define properties with the attribute not-null="true". Otherwise, an attempt to save a Cat may fail with an error indicating that there is no wingspan.

The *.hbm.xml mapping to corresponding to the table in Table 7.3 is shown in Listing 7.1.

Listing 7.1. Subclass Mapping
<hibernate-mapping>
      <class name="com.example.Animal">
            <id name="id" type="long" column="ID">
            <generator class="native"/></id>
            <discriminator column="discriminator"
            type="string"/>
            <property name="name" type="string" />
            <property name="weight" type="integer" />
            <subclass name="com.example.Cat">
                <property name="color" type="string"
                column="color"/>
                <property name="teeth" type="integer"
                column="teeth" />
            </subclass>
            <subclass name="com.example.Bird">
                <property name="color" type="string"
                column="color"/>
                <property name="wingspan" type="integer"
                column="wingspan" />
            </subclass>
      </class>
</hibernate-mapping>

Note that the subclass declarations in Listing 7.1 do not specify an id tag (or a timestamp or version tag). These must be declared in the base class.

If you wish to use multiple tables for your subclasses instead of a single table, you will actually be using a joined-subclass relationship. You can't use both a subclass and a joined subclass in the same class tag; you have to choose one strategy or the other.

Joined Subclasses

A joined subclass is used to define a multiple-table object hierarchy in Hibernate. For example, let's say we wish to persist objects of the type com.example.Animal, com.example.Cat, and com.example.Bird to three tables, one per class (Cat and Bird, of course, extend Animal). Instead of using a discriminator column (as per a normal subclass), the application will use a JOIN statement to mesh the tables together as needed (hence the name "joined subclass"). Animal records have the properties name and weight. Cat records define the additional properties color and teeth, Bird records the additional properties color and wingspan. So our Animal, Cat, and Bird records could be tracked using three tables, as shown Tables 7.4, 7.5, and 7.6.

Table 7.4. Animal Base Class

Id

Name

Weight

1

Bob

10

2

Ashe

8

3

Mika

2


Table 7.5. Cat Joined Subclass

Id

Color

Teeth

2

Gray

26


Table 7.6. Bird Joined Subclass

Id

Color

Wingspan

3

Blue

10


In this case, the primary key values are used to keep track of the appropriate class no discriminator is required.

The *.hbm.xml mapping corresponding to Table 7.4, Table 7.5, and Table 7.6 would be as shown in Listing 7.2.

Listing 7.2. Joined Subclass Mapping
<hibernate-mapping>
      <class name="com.example.Animal" table="Animal">
            <id name="id" type="long" column="ID">
                  <generator class="native"/></id>
            <property name="name" type="string" />
            <property name="weight" type="integer" />
            <joined-subclass name="com.example.Cat"
            table="Cat">
                <key column="ID" />
                <property name="color" type="string"
                column="color"/>
                <property name="teeth" type="integer"
                column="teeth" />
            </subclass>
            <subclass name="com.example.Bird" table="Bird">
                <key column="ID" />
                <property name="color" type="string"
                column="color"/>
                <property name="wingspan" type="integer"
                column="wingspan" />
             </subclass>
      </class>
</hibernate-mapping>

Note that the subclasses specify a key tag pointing back to the id property of com.example.Animal. As a reminder: you can't use both subclass and joined subclass in the same class tagyou'll need to choose one strategy or the other.

Components

In Hibernate terminology, a component refers to the notion of breaking up a table into pieces. For example, many User tables grow rather large because they contain information about several different aspects of the user. With some applications, it may be easier to map these aspects separately using components instead of a single monolithic user class.

The use of a component allows for certain interesting features. For example, setting a component to null is the same as setting all of the subvalues to null. Continuing the example of a User table, you could invalidate all of the user's address fields with a single callsimply setting the address component to nullinstead of naming the individual components.

You might even map multiple sequences but bind them to the same component, allowing your Java application to reuse an object to apply data in multiple places. For example, consider the mapping shown in Listing 7.3.

TIP

The use of components generally boils down to a question of the number of columns in a given table. For example, a user table with 50 columns might be an excellent candidate for the use of components. Generally speaking, I find components to be most useful when I am dealing with a legacy system, and I am more likely to model logical components with a one-to-one relationship for new development (especially if I have a core subset of the columns that will be used much more frequently than the rest).


Listing 7.3. Example Component Mapping
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping SYSTEM "C:\devenv\hibernate-2.1.2\src\net\sf\hibernate
\hibernate-mapping-2.0.dtd">
<hibernate-mapping>
  <class name="com.cascadetg.ch07.ComponentExample"
      table="componentexample">
    <id name="id" column="ID" type="string" unsaved-
    value="null">
      <generator class="uuid.hex"/>
    </id>
    <property name="name" column="name"
      type="string" length="50" not-null="true"/>
      <component name="homeAddress"
            class="com.cascadetg.ch07.AddressComponent">
          <property name="street" column="home_street"
          type="char" />
          <property name="city" column="home_city" type="char" />
      </component>
      <component
            name="workAddress"
            class="com.cascadetg.ch07.AddressComponent">
              <property name="street" column="work_street"
              type="string" />
              <property name="city" column="work_city"
              type="string" />
      </component>
  </class>
</hibernate-mapping>

The mapping file shown in Listing 7.3 would only have a single table (componentexample), but would correspond to two Java classes (ComponentExample and AddressComponent). The columns of the componentexample table would be id, name, home_street, home city, work_street, and work city.

Given this mapping, it would then be possible to set both the home and work address information using the same object, as shown in Listing 7.4.

Listing 7.4. Using Components
hibernateSession = sessionFactory.openSession();
myTransaction = hibernateSession.beginTransaction();

ComponentExample myMessage = new ComponentExample();
myMessage.setName("foo");

AddressComponent myAddressComponent = new AddressComponent();
myAddressComponent.setStreet("123 Anywhere");
myAddressComponent.setCity("Universal City");

myMessage.setHomeAddress(myAddressComponent);
myMessage.setWorkAddress(myAddressComponent);

hibernateSession.save(myMessage);

myTransaction.commit();

A component is used to break up a single monolithic table, whereas a one-to-one mapping is used to associate two different tables.