Typed relation (annotation workaround)

In chapter the section called “Typed relation (XML only)” we explained a typed relation. This approach is not possible with annotation mapping. There are two alternatives: First, TutorialReader has two fields billing_address_id, delivery_address_id. If you add a billing address to the reader, you set the type in ReaderAddress manually to “billing". Second, you map BillingAddress, DeliveryAddress and ReaderAddress as a inheritance structure. This approach is shown below: A tutorial reader has two addresses, a billing and a delivery address. Only these address types are allowed. Full source code is provided in the package: de.laliluna.relation.typed

ClassesTables

images/typed_classes.jpg

images/typed_tables.jpg

import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.JoinColumn;
import javax.persistence.OneToOne;
...... snip ..........
@Entity
public class TutorialReader implements Serializable{

   @OneToOne(cascade=CascadeType.ALL)
   @JoinColumn(name="billing_address_id")
   private BillingAddress billingAddress;

   @OneToOne(cascade=CascadeType.ALL)
   @JoinColumn(name="delivery_address_id")
   private DeliveryAddress deliveryAddress;

The ReaderAddress includes all common properties:

import java.io.Serializable;
import javax.persistence.DiscriminatorColumn;
import javax.persistence.DiscriminatorType;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Inheritance;
import javax.persistence.InheritanceType;
import javax.persistence.SequenceGenerator;

@Entity
@Inheritance(strategy=InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(name="type",discriminatorType=DiscriminatorType.STRING)
public class ReaderAddress implements Serializable {

   @Id
   @SequenceGenerator(name = "readeraddress_seq",
      sequenceName = "readeraddress_id_seq")
   @GeneratedValue(strategy=GenerationType.SEQUENCE,
      generator="readeraddress_seq")
   private Integer id;

   private String address;

   private String city;

@Inheritance(strategy=InheritanceType.SINGLE_TABLE) defines the inheritance strategy. All addresses will be kept in one table. The different addresses can be identified by a discriminator column. A discriminator column holds the type of the address. @DiscriminatorColumn(name="type",discriminatorType=DiscriminatorType.STRING)

Deliveryaddress and BillingAddress are fairly short.

@Entity
public class BillingAddress extends ReaderAddress {
   public BillingAddress() {
      super();
   }
   public BillingAddress(Integer id, String address, String city) {
      super(id,address,city);
   }
   private static final long serialVersionUID = 3313063223421102585L;
}
import javax.persistence.Entity;

@Entity
public class DeliveryAddress extends ReaderAddress {
   private static final long serialVersionUID = 8902940839248062796L;
   public DeliveryAddress(){
      super();
   }
   public DeliveryAddress(Integer id, String address, String city) {
      super(id,address,city);
   }
}

The following tables are generated:

CREATE TABLE ttutorialreader
(
  id int4 NOT NULL,
  name varchar(255),
  billingaddress_fk int4,
  deliveryaddress_fk int4,
  PRIMARY KEY (id),
  FOREIGN KEY (billing_address_id)
      REFERENCES annotation.readeraddress (id) MATCH SIMPLE
      ON UPDATE NO ACTION ON DELETE NO ACTION,
  FOREIGN KEY (delivery_address_id)
      REFERENCES annotation.readeraddress (id) MATCH SIMPLE
      ON UPDATE NO ACTION ON DELETE NO ACTION
) ;
CREATE TABLE readeraddress
(
  "type" varchar(31) NOT NULL,
  id int4 NOT NULL,
  address varchar(255),
  city varchar(255),
  PRIMARY KEY (id)
)

Samples of use:

/* create and set relation */
TutorialReader reader = new TutorialReader();
reader.setName("Sebastian");
BillingAddress billing = new BillingAddress(null, "Alte Landstrasse",
      "Frankfurt");
DeliveryAddress delivery = new DeliveryAddress(null, "Neue Landstrasse",
      "Frankfurt");
reader.setBillingAddress(billing);
reader.setDeliveryAddress(delivery);
session.save(reader);

/* select all billing addresses */
   List list = session.createQuery("from BillingAddress").list();

/* select tutorial reader with billing address in Frankfurt */
List    list = session.createQuery("from TutorialReader r where
r.billingAddress.address='Alte Landstrasse'").list();