Relationships

The entity tutorial only showed one-to-many and many-to-one relationships. This tutorial will show you one-to-one and many-to-many relationships.

One to One

There is a unidirectional one to one relationship defined between the Customer and Address. Customer defines the uni directional relationship.

   @OneToOne(cascade = {CascadeType.ALL})
   @JoinColumn(name = "ADDRESS_ID")
   public Address getAddress()
   {
      return address;
   }

CascadeType.ALL specifies that when a Customer is created, if there is any Address association, then that Address will be created as well(CascadeType.PERSIST). If the Customer is deleted from persistence storage, the Address table will be deleted(CascadeType.REMOVE). If a Customer instance is reattached to persistence storage, any changes to the Address collection will be merged with persistence storage (CascadeType.MERGE).

Many To Many

There is a mant to many relationship between Customer and Flight. In order to have a many to many relationship there needs to be a distinct join table that maps the many to many relationship. This is called an association table. You can have JBoss automatically generate the association table for you, or you can use the @JoinTable annotation to define it yourself. If you use @JoinTable it must be defined on both sides of the bi-directional relationship. Let's look at the Customer side of the relationship

   @ManyToMany(cascade = {CascadeType.PERSIST, CascadeType.MERGE}, fetch = FetchType.EAGER, mappedBy="customers")

The mappedBy attribute states that the Flight.customers property is responsible for mapping and managing the relationship. The spec allows for multiple join and inverse join columns. See the Composite Primary Key tutorial for more information.

Let's look at the other side of the relationship in Flight.

   @ManyToMany(cascade = {CascadeType.PERSIST, CascadeType.MERGE}, fetch = FetchType.EAGER)
   @JoinTable(table = @Table(name = "flight_customer_table"),
                     joinColumns = {@JoinColumn(name = "FLIGHT_ID")},
                     inverseJoinColumns = {@JoinColumn(name = "CUSTOMER_ID")})
   public Set<Customer> getCustomers()
   {
      return customers;
   }

The database associate table will look like this:

   create table FLIGHT_CUSTOMER_TABLE (
      CUSTOMER_ID integer,
      FLIGHT_ID integer
   );

Building and Running

To build and run the example, make sure you have ejb3.deployer installed in JBoss 4.0.x and have JBoss running. See the reference manual on how to install EJB 3.0.
Unix:    $ export JBOSS_HOME=<where your jboss 4.0 distribution is>
Windows: $ set JBOSS_HOME=<where your jboss 4.0 distribution is>
$ ant
$ ant run

run:
     [java] 2004-10-07 14:39:23,103 INFO org.jboss.remoting.InvokerRegistry[main] - Failed to load soap remoting transpo
rt: org/apache/axis/AxisFault
     [java] Air France customers
     [java] Bill
     [java] Monica
     [java] USAir customers
     [java] Molly

The INFO message you can ignore. It will be fixed in later releases of JBoss 4.0.

View the tables and rows

You can view the tables created by JBoss by going to the Hypersonic SQL service, scrolling down to the startDatabaseManager button and clicking it. A Hypersonic SQL window will be minimized, but you can open it up to look at the tables and do queries.