Mapping Persistent Objects

66
1 Mapping Persistent Mapping Persistent Objects Objects Entities represent data in the database, so changes to an entity bean result in changes to the database. That's ultimately the purpose of an entity bean: to provide programmers with a simpler mechanism for accessing and changing data. It is much easier to change a customer's name by calling Customer.setName( ) than by executing an SQL command against the database.

description

Mapping Persistent Objects. Entities represent data in the database, so changes to an entity bean result in changes to the database. That's ultimately the purpose of an entity bean: to provide programmers with a simpler mechanism for accessing and changing data. - PowerPoint PPT Presentation

Transcript of Mapping Persistent Objects

11

Mapping Persistent ObjectsMapping Persistent Objects Entities represent data in the database, so

changes to an entity bean result in changes to the database.

That's ultimately the purpose of an entity bean: to provide programmers with a simpler mechanism for accessing and changing data.

It is much easier to change a customer's name by calling Customer.setName( ) than by executing an SQL command against the database.

22

Mapping Persistent ObjectsMapping Persistent Objects When a new entity is created and persisted into the

entity manager service, a new record must be inserted into the database and a bean instance must be associated with that data.

As the entity is used and its state changes, these changes must be synchronized with the data in the database: entries must be inserted, updated, and removed.

The process of coordinating the data represented by a bean instance with the database is called persistence.

33

The Customer BeanThe Customer Bean

The Customer bean is a simple entity bean that models the concept of a cruise customer or passenger, but its design and use are applicable across many commercial domains.

44

The Bean ClassThe Bean ClassThe Customer bean class is a plain Java

object that you map to your relational database.

It has fields that hold state and, optionally, it has getter and setter methods to access this state.

It must have, at minimum, a no-argument constructor:

55

The Bean ClassThe Bean Classpackage com.titan.domain;package com.titan.domain;

import javax.persistence.*;import javax.persistence.*;

@Entity@Entity

public class Customer implements java.io.Serializable {public class Customer implements java.io.Serializable {

private long id;private long id;

private String firstName;private String firstName;

private String lastName;private String lastName;

@Id@Id

public long getId( ) { return id; }public long getId( ) { return id; }

public void setId(long id) { this.id = id; }public void setId(long id) { this.id = id; }

public String getFirstName( ) { return firstName; }public String getFirstName( ) { return firstName; }

public void setFirstName(String firstName) { this.firstName = public void setFirstName(String firstName) { this.firstName = firstName; }firstName; }

public String getLastName( ) { return lastName; }public String getLastName( ) { return lastName; }

public void setLastName(String lastName) { this.lastName = public void setLastName(String lastName) { this.lastName = lastName; }lastName; }

66

The Bean ClassThe Bean Class Here is the table definition the persistence provider

is assuming you are mapping to:

create table Customer(

id long primary key not null,

firstName VARCHAR(255),

lastName VARCHAR(255)

);

The @javax.persistence.Entity annotation tells the persistence provider that your class can be persisted:

package javax.persistence;

@Target(TYPE) @Retention(RUNTIME)

public @interface Entity

{

String name( ) default "";

}

77

The Bean ClassThe Bean Class The @Entity annotation has one name( )

attribute. This name is used to reference the entity within

an EJB QL expression. If you do not provide a value for this attribute, the

name defaults to the unqualified name of the bean class.

How you apply the @javax.persistence.Id annotation determines whether you will use the Java bean style for declaring your persistent properties or whether you will use Java fields.

88

The Bean ClassThe Bean Class

If you place the @Id annotation on a getter method, as done in this example, then you must apply any other mapping annotations on getter and setter methods in the class.

The provider will also assume that any other getter and setter methods in your class represent persistent properties and will automatically map them based on their base name and type.

99

The Bean ClassThe Bean Class@Entity

public class Customer implements java.io.Serializable {

@Id

private long id;

private String firstName;

private String lastName;

public long getId( ) { return id; }

public void setId(long id) { this.id = id; }

public String getFirstName( ) { return firstName; }

public void setFirstName(String firstName) { this.firstName = firstName; }

public String getLastName( ) { return lastName; }

public void setLastName(String lastName) { this.lastName = lastName; }

}

1010

The Bean ClassThe Bean Class Here, we have placed the @Id annotation on a

member field of the class. The persistence provider will also assume that any

other member fields of the class are also persistent properties and will automatically map them based on their base name and type.

Any mapping annotations must be placed on member fields in this example, not on getter or setter methods.

Here, we are really defining the access type - that is, whether our relational mappings are defined on the fields or the methods of a class.

1111

XML Mapping FileXML Mapping File If you do not want to use annotations to identify

and map your entity beans, you can alternatively use an XML mapping file to declare this metadata.

By default, the persistence provider will look in the META-INF directory for a file named orm.xml, or you can declare the mapping file in the <mapping-file> element in the persistence.xml deployment descriptor.

Here's how the Customer entity mapping would look in XML:

1212

XML Mapping FileXML Mapping File<entity-mappings>

<entity class="com.titan.domain.Customer" access="PROPERTY">

<attributes>

<id name="id"/>

</attributes>

</entity>

</entity-mappings>

The <entity> element defines the entity class and access type: PROPERTY or FIELD.

Like annotated classes, the persistence provider will assume that any other property in your class is a persistent property, and you do not have to explicitly define them.

1313

Basic Relational MappingBasic Relational Mapping A developer can take two directions when

implementing entity beans. Some applications start from a Java object model

and derive a database schema from this model. Other applications have an existing database

schema from which they have to derive a Java object model.

If you are creating a database schema from a Java object model, most persistence vendors have tools that can autogenerate database schemas based on the annotations or XML metadata you provide in your code.

1414

Basic Relational MappingBasic Relational Mapping

If you have an existing database schema, many vendors have tools that can generate Java entity code directly from it.

Sometimes, though, this generated code is not very object-oriented and doesn't map to your database very well.

Luckily, the Java Persistence specification provides the necessary mapping capabilities to facilitate this problem.

1515

Elementary Schema MappingsElementary Schema Mappings Here's the table definition in SQL:

create table CUSTOMER_TABLE

(

CUST_ID integer primary key not null,

FIRST_NAME varchar(20) not null

lastName varchar(255) not null,

);

We want to change the table name and the column We want to change the table name and the column names of the id and firstName properties. names of the id and firstName properties.

We also want firstName to have a not-null We also want firstName to have a not-null constraint and want to set the VARCHAR length to constraint and want to set the VARCHAR length to 20. 20.

1616

Elementary Schema MappingsElementary Schema Mappings Let's modify our original Customer entity class

and add the mapping annotations:

package com.titan.domain;

import javax.persistence.*;

@Entity

@Table

(name="CUSTOMER_TABLE")

public class Customer implements java.io.Serializable {

private long id;

private String firstName;

private String lastName;

1717

Elementary Schema MappingsElementary Schema Mappings@Id

@Column(name="CUST_ID", nullable=false, columnDefinition="integer")

public long getId( ) { return id; }

public void setId(long id) { this.id = id; }

@Column(name="FIRST_NAME", length=20, nullable=false)

public String getFirstName( ) { return firstName; }

public void setFirstName(String firstName) { this.firstName = firstName; }

public String getLastName( ) { return lastName; }

public void setLastName(String lastName) { this.lastName = lastName; }

}

1818

@Table@Table

Let's look at the full definition of this Let's look at the full definition of this annotation:annotation:

package javax.persistence;package javax.persistence;

@Target({TYPE}) @Retention(RUNTIME)@Target({TYPE}) @Retention(RUNTIME)

public @interface Tablepublic @interface Table

{{

String name( ) default "";String name( ) default "";

String catalog( ) default "";String catalog( ) default "";

String schema( ) default "";String schema( ) default "";

UniqueConstraint uniqueConstraints( ) default {};UniqueConstraint uniqueConstraints( ) default {};

}}

1919

@Table@Table

The catalog( ) and schema( ) attributes are self-explanatory, as they identify the relational catalog and schema the table belongs to:

public @interface UniqueConstraint

{

String[] columnNames( );

}

2020

@Column@Column @javax.persistence.Column annotation describes

how a particular field or property is mapped to a specific column in a table:

public @interface Column

{

String name( ) default "";

boolean unique( ) default false;

boolean nullable( ) default true;

boolean insertable( ) default true;

boolean updatable( ) default true;

String columnDefinition( ) default "";

String table( ) default "";

int length( ) default 255;

int precision( ) default 0;

int scale( ) default 0;

}

2121

@Column@Column The @Column annotation has the XML equivalent

in the <column> element. This element is a subelement of the attribute mapping types <id>, <basic>, <temporal>, <lob>, and <enumerated> that are described later in this chapter.<basic name="lastName"><basic name="lastName"> <column name=""<column name="" unique="true"unique="true" nullable="true"nullable="true" insertable="true"insertable="true" updatable="true"updatable="true" column-definition=""column-definition="" table=""table="" length=""length="" precision=""precision="" scale=""scale="" />/></basic></basic>

2222

Primary KeysPrimary Keys

Primary keys can map to one or more properties and must map to one of the following types:

any Java primitive type (including wrappers), java.lang.String , or a primary-key class composed of

primitives and/or strings. Let's first focus on simple one-property

primary keys.

2323

@Id@IdThe @javax.persistence.Id annotation

identifies one or more properties that make up the primary key for your table:package javax.persistence;package javax.persistence;

@Target({METHOD, FIELD}) @Retention(RUNTIME)@Target({METHOD, FIELD}) @Retention(RUNTIME)

public @interface Idpublic @interface Id

{{

}}

You can generate the primary key for your entity beans manually or have the persistence provider do it for you.

2424

@Id@Id

When you want provider-generated keys, you have to use the @javax.persistence.GeneratedValue annotation:

package javax.persistence;

@Target({METHOD, FIELD}) @Retention(RUNTIME)public @interface GeneratedValue{ GenerationType strategy( ) default AUTO; String generator( ) default "";}

public enum GenerationType{ TABLE, SEQUENCE, IDENTITY, AUTO}

2525

@Id@Id Persistence providers are required to provide key

generation for primitive primary keys. You can define the type of primary generator you

would like to have using the strategy( ) attribute. The GeneratorType.AUTO strategy is the most

commonly used configuration. The AUTO strategy tells the persistence provider

that you are allowing it to generate the key for you. The IDENTITY strategy uses a special column

type, available in many database implementations, for creating primary keys.

2626

Table GeneratorsTable Generators The TABLE strategy designates a user-defined

relational table from which the numeric keys will be generated. A relational table with the following logical structure is used:create table GENERATOR_TABLE

(

PRIMARY_KEY_COLUMN

VARCHAR not null,

VALUE_COLUMN

long not null

);

This annotation can be applied to a class or to the method or field of the primary key:

2727

Table GeneratorsTable Generatorspackage javax.persistence;

@Target({TYPE, METHOD, FIELD}) @Retention(RUNTIME)

public @interface TableGenerator

{

String name( );

String table( ) default "";

String catalog( ) default "";

String schema( ) default "";

String pkColumnName( ) default "";

String valueColumnName( ) default "";

String pkColumnValue( ) default "";

int allocationSize( ) default 50;

UniqueConstraint[] uniqueConstraints( ) default {};

}

2828

Table GeneratorsTable Generators Let's look at how you would actually use this

generator on the Customer entity:package com.titan.domain

import javax.persistence.*;

@Entity

public class Customer implements java.io.Serializable {

private long id;

private String firstName;

private String lastName;

@TableGenerator(name="CUST_GENERATOR"

table="GENERATOR_TABLE"

pkColumnName="PRIMARY_KEY_COLUMN"

valueColumnName="VALUE_COLUMN"

pkColumnValue="CUST_ID"

allocationSize=10)

2929

Table GeneratorsTable Generators@Id

@GeneratedValue

(strategy=GenerationType.TABLE,

generator="CUST_GENERATOR")

public long getId( ) { return id; }

public void setId(long id) { this.id = id; }

public String getFirstName( ) { return firstName; }

public void setFirstName(String firstName)

{ this.firstName = firstName; }

public String getLastName( )

{ return lastName; }

public void setLastName(String lastName)

{ this.lastName = lastName;

3030

Table GeneratorsTable Generators Now if you allocate and persist( ) a Customer entity, the

id property will be autogenerated when the persist() operation is called.

Let's look at how this would be defined within XML:<entity-mappings> <entity class="com.titan.domain.Customer" access="PROPERTY"> <table-generator name="CUST_GENERATOR" table="GENERATOR_TABLE" pk-column-name="PRIMARY_KEY_COLUMN" value-column-name="VALUE_COLUMN" pk-column-value="CUST_ID" allocation-size="10"/> <attributes> <id name="id"> <generated-value strategy="TABLE" generator="CUST_GENERATOR"/> </id> </attributes> </entity></entity-mappings>

3131

Sequence GeneratorsSequence Generators Some RDBMs, specifically Oracle, have an

efficient, built-in structure to generate IDs sequentially. This is the SEQUENCE generator strategy. This generator type is declared via the @javax.persistence.SequenceGenerator :package javax.persistence;

@Target({METHOD, TYPE, FIELD}) @Retention(RUNTIME)

public @interface SequenceGenerator

{

String name( );

String sequenceName( )

default "";

int initialValue( ) default 1;

int allocationSize( ) default 50;

}

3232

Sequence GeneratorsSequence GeneratorsLet's again look at applying the SEQUENCE

strategy on our Customer entity bean:

package com.titan.domain

import javax.persistence.*;

@Entity

@Table(name="CUSTOMER_TABLE")

@SequenceGenerator(name="CUSTOMER_SEQUENCE",

sequenceName="CUST_SEQ")

public class Customer implements java.io.Serializable {

private long id;

private String firstName;

private String lastName;

3333

Sequence GeneratorsSequence Generators@Id

@GeneratedValue(strategy=GenerationType.SEQUENCE, generator="CUSTOMER_SEQUENCE")

public long getId( ) { return id; }

public void setId(long id) { this.id = id; }

public String getFirstName( ) { return firstName; }

public void setFirstName(String firstName)

{ this.firstName = firstName; }

public String getLastName( ) { return lastName; }

public void setLastName(String lastName)

{ this.lastName = lastName; }

}

This example is a little different from our TABLE strategy example in that the generator is declared on the bean's class instead of directly on the property.

3434

Sequence GeneratorsSequence Generators

TABLE and SEQUENCE generators can be defined in either place.

As with the TABLE generation type, the primary key is autogenerated when the EntityManager.persist( ) operation is performed.

3535

Sequence GeneratorsSequence Generators Let's look at the XML equivalent for this mapping:

<entity-mappings>

<entity class="com.titan.domain.Customer" access="PROPERTY">

<sequence-generator name="CUSTOMER_SEQUENCE"

sequence-name="CUST_SEQ"

initial-value="0"

allocation-size="50"/>

<attributes>

<id name="id">

<generated-value strategy="SEQUENCE" generator="CUSTOMER_SEQUENCE"/>

</id>

</attributes>

</entity>

</entity-mappings>

3636

Primary-Key Classes and Primary-Key Classes and Composite KeysComposite Keys

Sometimes relational mappings require a primary key to be composed of multiple persistent properties.

For instance, let's say that our relational model specified that our Customer entity should be identified by both its last name and its Social Security number instead of an autogenerated numeric key.

These are called composite keys. The Java Persistence specification provides multiple ways to map this type of model.

One is through the @javax.persistence.IdClass annotation; The other is through the @javax.persistence.EmbeddedId

annotation.

3737

@IdClass@IdClass

@IdClass is a class-level annotation and specifies what primary-key class you should use when interacting with the entity manager.

@Target(TYPE)

@Retention(RUNTIME)

public @interface IdClass

{

Class value( );

}

First, let's define our primary-key class:

3838

@IdClass@IdClasspackage com.titan.domain;

public class CustomerPK

implements java.io.Serializable {

private String lastName;

private long ssn;

public CustomerPK( ) {}

public CustomerPK(String lastName, long ssn)

{

this.lastName = lastName;

this.ssn = ssn;

}

public String getLastName( ) { return this.lastName; }

public void setLastName(String lastName) { this.lastName = lastName; }

3939

@IdClass@IdClasspublic long getSsn( ) { return ssn; }

public void setSsn(long ssn) { this.ssn = ssn; }

public boolean equals(Object obj)

{

if (obj == this) return true;

if (!(obj instanceof CustomerPK)) return false;

CustomerPK pk = (CustomerPK)obj;

if (!lastName.equals(pk.lastName)) return false;

if (ssn != pk.ssn) return false;

return true;

}

public int hashCode( )

{

return lastName.hashCode( ) + (int)ssn;

}

}

4040

@IdClass@IdClass The primary-key class must meet these

requirements:

It must be serializable. It must have a public no-arg constructor. It must implement the equals( ) and hashCode( )

methods.

Our Customer bean must have the same exact properties as the CustomerPK class, and these properties are annotated with multiple @Id annotations:

4141

@IdClass@IdClasspackage com.titan.domain;

import javax.persistence.*;

@Entity

@IdClass(CustomerPK.class)

public class Customer implements java.io.Serializable {

private String firstName;

private String lastName;

private long ssn;

public String getFirstName( ) { return firstName; }

public void setFirstName(String firstName)

{ this.firstName = firstName; }

@Id

public String getLastName( ) { return lastName; }

public void setLastName(String lastName) { this.lastName = lastName; }

4242

@IdClass@IdClass

@Id

public long getSsn( ) { return ssn; }

public void setSsn(long ssn) { this.ssn = ssn; }

}

Let's now look at the XML mapping equivalent to @IdClass:

<entity-mappings>

<entity class="com.titan.domain.Customer" access="PROPERTY">

<id-class>com.titan.domain.CustomerPK</id-class>

<attributes>

<id name="lastName"/>

<id name="ssn"/>

</attributes>

</entity>

</entity-mappings>

4343

@EmbeddedId@EmbeddedId A different way to define primary-key classes and

composite keys is to embed the primary-key class directly in your bean class.

The @javax.persistence.EmbeddedId annotation is used for this purpose in conjunction with the @javax.persistence.Embeddable annotation:

package javax.persistence;

public @interface EmbeddedId

{

}

public @interface AttributeOverrides

{

AttributeOverride[] value( );

}

4444

@EmbeddedId@EmbeddedIdpublic @interface AttributeOverride

{

String name( );

Column[] column( ) default {};

}

public @interface Embeddable

{

}

There are two ways to map the properties of your primary-key class to columns in your table.

One is to specify the @Column mappings within the primary-key class source code;

The other is to use @AttributeOverrides.

4545

Property MappingsProperty Mappings

Java Persistence has mappings for JDBC Blobs and Clob s, serializable objects, and embeddable objects, as well as optimistic concurrency with version properties. We will discuss all of these.

4646

@Transient@Transient

You may have properties that you don't want to be persistent, and, therefore, the default behavior is inappropriate.

This is where the @javax.persistence.Transient annotation comes in:

@Entity

public class Customer implements java.io.Serializable {

private String firstName;

private CustomerPK pk;

public String getFirstName( ) { return firstName; }

public void setFirstName(String firstName) { this.firstName = firstName;

}

4747

@Transient@Transient

@Transient

public String getLastName( ) { return pk.getLastName( ); }

@Transient

public long getSsn( ) { return pk.getSsn( ); }

@EmbeddedId

public PK getPk( ) { return pk; }

public void setPk(CustomerPK pk) { this.pk = pk; }

}

4848

@Transient@TransientHere is what the XML equivalent looks like:

<entity-mappings>

<embeddable class="com.titan.domain.CustomerPK" access-type="PROPERTY">

<embeddable-attribute name="lastName">

<column name="CUSTOMER_LAST_NAME"/>

</embeddable-attribute>

<embeddable-attribute name="ssn">

<column name="CUSTOMER_SSN"/>

</embeddable-attribute>

</embeddable>

<entity class="com.titan.domain.Customer" access="PROPERTY">

<attributes>

<embedded-id name="pk"/>

<transient name="lastName"/>

<transient name="ssn"/>

</attributes>

</entity>

</entity-mappings>

4949

@Basic and FetchType@Basic and FetchType The @Basic annotation is the simplest form of

mapping for a persistent property. This is the default mapping type for properties which

are primitives, primitive wrapper types, java.lang.String, byte[ ], Byte[ ], char[ ], Character[ ], java.math.BigInteger, java.math.BigDecimal, java.util.Date, java.util.Calendar, java.sql.Date, java.sql.Time , and java.sql.Timestamp .

You do not need to tell your persistence manager explicitly that you're mapping a basic property because it can usually figure out how to map it to JDBC using the property's type.

5050

@Basic and FetchType@Basic and FetchType

public @interface Basic

{

FetchType fetch( ) default EAGER;

boolean optional( ) default true;

}

public enum FetchType

{

LAZY, EAGER

}

Let's take our Customer entity and show how to use the @Basic annotation:

5151

@Basic and FetchType@Basic and FetchTypepackage com.titan.domain

import javax.persistence.*;

@Entity

public class Customer implements java.io.Serializable {

private long id;

private String firstName;

private String lastName;

@Id

@GeneratedValue

public long getId( ) { return id; }

public void setId(long id) { this.id = id; }

@Basic(fetch=FetchType.LAZY, optional=false)

public String getFirstName( ) { return firstName; }

public void setFirstName(String firstName)

{ this.firstName = firstName; }

5252

@Basic and FetchType@Basic and FetchType The @Basic annotation also has an XML

equivalent:

<entity-mappings>

<entity class="com.titan.domain.Customer" access="PROPERTY">

<attributes>

<id name="id">

<generated-value/>

</id>

<basic name="firstName" fetch="LAZY" optional="false"/>

<basic name="lastName" fetch="LAZY" optional="false"/>

</attributes>

</entity>

</entity-mappings>

5353

@Lob@Lob

Sometimes your persistent properties require a lot of memory.

The @javax.persistence.Lob annotation is used to map these large object types.

Java Persistence allows you to map some basic types to a @Lob and have the persistence manager handle them internally as either a Blob or a Clob, depending on the type of the property:

5454

@Lob@Lobpackage javax.persistence;

public @interface Lob

{

}

Properties annotated with a @Lob are persisted in a:

Blob if the Java type is byte[ ], Byte[ ], or java.io.Serializable

Clob if the Java type is char[ ], Character[ ], or java.lang.String

5555

@Enumerated@Enumerated The @Enumerated annotation maps Java enum types

to the database. It is used in conjunction with the @Basic annotation

and lets you specify additional fetch semantics:

package javax.persistence;

public enum EnumType

{

ORDINAL,

STRING

}

public @interface Enumerated

{

EnumType

value( ) default ORDINAL;

}

5656

@Enumerated@Enumerated A Java enum property can be mapped either to the

string representation or to the numeric ordinal number of the enum value.

For example, let's say we want a Customer entity property that designates the kind of customer that is purchasing a reservation.

This could be represented in a Java enum called CustomerType with the enum values UNREGISTERED, REGISTERED, or BIG_SPENDAH. We would do it as follows:

5757

@Enumerated@Enumeratedpackage com.titan.domain;

import javax.persistence.*;

public enum CustomerType

{

UNREGISTERED,

REGISTERED,

BIG_SPENDAH

}

@Entity

public class Customer implements java.io.Serializable {

private long id;

private String firstName;

private String lastName;

private CustomerType customerType;

@Id

@GeneratedValue

public long getId( ) { return id; }

public void setId(long id) { this.id = id;

5858

@Enumerated@Enumeratedpublic String getFirstName( )

{ return firstName; }

public void setFirstName(String firstName)

{ this.firstName = firstName; }

public String getLastName( )

{ return lastName; }

public void setLastName(String lastName)

{ this.lastName = lastName; }

@Enumerated

(EnumType.STRING)

public CustomerType getCustomerType( )

{ return customerType; }

public void setCustomerType(CustomerType type)

{ customerType = type; }

}

5959

@Enumerated@Enumerated Here's the XML equivalent:

<entity-mappings>

<entity class="com.titan.domain.Customer" access="PROPERTY">

<attributes>

<id name="id">

<generated-value/>

</id>

<basic name="customerType">

<enumerated>STRING</enumerated>

</basic>

</attributes>

</entity>

</entity-mappings>

6060

Multitable Mappings with Multitable Mappings with @SecondaryTable@SecondaryTable

Sometimes you have to deal with one logical entity that is stored in two different tables.

You want one entity bean class to represent your object, but it is mapped into two different tables because you're working with a legacy database model.

Java Persistence allows you to map an entity bean class to one or more tables using the @javax.persistence.SecondaryTable annotation.

For example, let's say our Customer bean has properties that define the address of the Customer, but the address data is stored in a separate table.

6161

Multitable Mappings with Multitable Mappings with @SecondaryTable@SecondaryTable

Here's what the tables would look like:

create table CUSTOMER_TABLE

(

CUST_ID integer Primary Key Not Null,

FIRST_NAME varchar(20) not null,

LAST_NAME varchar(50) not null

);

create table ADDRESS_TABLE

(

ADDRESS_ID integer primary key not null,

STREET varchar(255) not null,

CITY varchar(255) not null,

STATE varchar(255) not null

);

6262

Multitable Mappings with Multitable Mappings with @SecondaryTable@SecondaryTable

To use the @SecondaryTable annotation, the primary key columns of the ADDRESS_TABLE must be joinable with one or more columns in the CUSTOMER_TABLE:public @interface SecondaryTable

{

String name( );

String catalog( ) default "";

String schema( ) default "";

PrimaryKeyJoinColumn[] pkJoinColumns( ) default {};

UniqueConstraint[] uniqueConstraints( ) default {};

}

public @interface PrimaryKeyJoinColumn

{

String name( ) default "";

String referencedColumnName( ) default "";

String columnDefinition( ) default "";

}

6363

Multitable Mappings with Multitable Mappings with @SecondaryTable@SecondaryTable

The referencedColumnName( ) attribute represents the column name in the CUSTOMER_TABLE that is used to join with the ADDRESS_TABLE.

package com.titan.domain;

import javax.persistence.*;

import com.acme.imaging.JPEG;

@Entity

@Table(name="CUSTOMER_TABLE")

@SecondaryTable(name="ADDRESS_TABLE",

pkJoinColumns={

@PrimaryKeyJoinColumn(name="ADDRESS_ID")})

public class Customer implements java.io.Serializable {

...

6464

Multitable Mappings with Multitable Mappings with @SecondaryTable@SecondaryTable

The next step is to map the street, city, and state properties to columns in the ADDRESS_TABLE.

If you remember the full @Column annotation, one of the attributes we did not go over fully is the table( ) attribute. You use this to map the address properties to your secondary table:package com.titan.domain;

import javax.persistence.*;

import com.acme.imaging.JPEG;

@Entity

@Table(name="CUSTOMER_TABLE")

@SecondaryTable(name="ADDRESS_TABLE",

pkJoinColumns={

@PrimaryKeyJoinColumn(name="ADDRESS_ID")})

6565

Multitable Mappings with Multitable Mappings with @SecondaryTable@SecondaryTable

public class Customer implements java.io.Serializable {

private long id;

private String firstName;

private String lastName;

private String street;

private String city;

private String state;

...

@Column(name="STREET", table="ADDRESS_TABLE")

public String getStreet( ) { return street; }

public void setStreet(String street) { this.street = street; }

@Column(name="CITY", table="ADDRESS_TABLE")

public String getCity( ) { return city; }

public void setCity(String city) { this.city = city; }

@Column(name="STATE", table="ADDRESS_TABLE")

public String getState( ) { return state; }

public void setState(String state) { this.state = state; }

...

6666

Multitable Mappings with Multitable Mappings with @SecondaryTable@SecondaryTable

What do you do if you have more than one secondary table?

For example, let's say that you want to embed credit card properties, but this information was also stored in another table.

In that instance, you would use the @SecondaryTables annotation.