Exercise 7.2: Inverse Relationships

Exercise 7.2: Inverse Relationships

This exercise illustrates what happens when you modify only the inverse side of a relationship.

Start Up JBoss

There is no need to start up JBoss in this example because standalone persistence is being used.

Initialize the Database

The database tables will be created when the clients in this exercise run. The database is an in-memory-only database and will not be available when the program completes.

Build the Example Programs

Perform the following steps:

  1. Open a command prompt or shell terminal and change to the ex07_2 directory created by the extraction process.

  2. Set the JAVA_HOME and JBOSS_HOME environment variables to point to where your JDK and JBoss 4.0 are installed. Examples:


    C:\workbook\ex07_2> set JAVA_HOME=C:\jdk1.5.0
    C:\workbook\ex07_2> set JBOSS_HOME=C:\jboss-4.0.x


    $ export JAVA_HOME=/usr/local/jdk1.5.0
    $ export JBOSS_HOME=/usr/local/jboss-4.0

  3. Add ant to your execution path. Ant is the build utility.


    C:\workbook\ex07_2> set PATH=..\ant\bin;%PATH%


    $ export PATH=../ant/bin:$PATH

  4. Perform the build by typing ant.

The titan.jar will be built. This JAR contains all the client and entity classes used in this example.

Examine the Entities

This exercise implements all of the entities from Chapter 7. You can find the implementations of the Ship, Cabin, Cruise, Customer, Phone, CreditCard, and Reservation entity classes in the com.titan.domain package in the src directory of the exercise. Take a moment to browse these files. We will not go over the implementation of these files because it is already discussed in detail in Chapter 7.

Examine Client1

Client1 illustrates an example of manipulating the inverse side of an @OneToOne relationship. It creates a CreditCard instance, sets the customer property of this relationship, and persists the CreditCard. It shows that since the CreditCard is the inverse side of the Customer-CreditCard relationship, the relationship is not stored in the database. Let's examine this file.

package com.titan.clients;

import javax.persistence.EntityManagerFactory;
import javax.persistence.EntityManager;
import javax.persistence.EntityTransaction;
import javax.persistence.Persistence;

import com.titan.domain.*;

public class Client1
   public static void main(String[] args) throws Exception
      EntityManagerFactory factory =

Because we're not running this example inside an application server, we need to fetch an EntityManagerFactory to obtain EntityManager instances with which we can work:

         Customer cust = createCustomerAddress(factory);
         createCreditCard(factory, cust);
         factory.close( );

First, we create a Customer in the database using the createCustomerAddress( ) method. We will not go over the details of this method because it is the same as the method in Exercise 7.1. Next, a CreditCard is added to the Customer within the createCreditCard( ) method:

   public static Customer createCreditCard(
              EntityManagerFactory factory, Customer cust)
      CreditCard card = new CreditCard( );
      card.setExpirationDate(new java.util.Date( ));
      card.setNameOnCard("William Burke");
      card.setCreditOrganization("Capital One");

This method starts by allocating an instance of a CreditCard entity. Notice that the customer property is set with the detached customer we created earlier in the program.

      EntityManager manager = factory.createEntityManager( );
      try {
         manager.getTransaction().begin( );
         manager.getTransaction().commit( );

Next, the CreditCard instance is persisted in the database within a resource-local transaction. Because CreditCard is the inverse side of the @OneToOne relationship between Customer and CreditCard, the relationship will not be wired in the database even though we set CreditCard's customer property.

         // Show that card.getCustomer( ) returns null

         manager.clear( );
         CreditCard cardCopy = manager.find(CreditCard.class, card.getId( ));
         System.out.println("should be null: " + cardCopy.getCustomer( ));

We begin a new resource-local transaction to retrieve a new copy of the CreditCard. The card's customer property is output to show that the related Customer instance is null.

         manager.getTransaction().begin( );
         System.out.println("now set the owning side of the relationship");
         Customer custCopy = manager.find(Customer.class, cust.getId( ));
         manager.getTransaction().commit( );

The relationship is then set correctly. The code retrieves a managed instance of the Customer and calls its setCreditCard( ) method. Because the Customer entity is the owning side of the relationship, the relationship is persisted when the transaction commits:

         manager.clear( );
         cardCopy = manager.find(CreditCard.class, card.getId( ));
         System.out.println("should be set now: " +
                             cardCopy.getCustomer().getFirstName( ));
      } finally {
         manager.close( );
      return cust;

Finally, a new copy of the CreditCard is fetched from the database to show that the Customer relationship is now set.

Run Client1

Run the Client1 application by invoking ant run.client1 at the command prompt. Remember to set your JBOSS_HOME and PATH environment variables. This is the output:

     [java] Create 1st Customer
     [java] Address was also persisted with auto-generated key: 1
     [java] Return detached Customer instance: 1
     [java] should be null: null
     [java] now set the owning side of the relationship
     [java] should be set now: Bill

 Python   SQL   Java   php   Perl 
 game development   web development   internet   *nix   graphics   hardware 
 telecommunications   C++ 
 Flash   Active Directory   Windows