The following sections enumerate the myriad of field mappings EJB persistence supports. EJB augments the persistence metadata covered in Chapter 5, Metadata with many new object-relational annotations. As we explore the library of standard mappings, we introduce each of these enhancements in context.
| ![[Note]](img/note.gif) | Note | 
|---|---|
| Kodo supports many additional field types, and allows you to create custom mappings for unsupported field types or database schemas. See the Reference Guide's Chapter 7, Mapping for complete coverage of Kodo EJB's mapping capabilities. | 
A basic field mapping stores the field value directly into a database column. The following field metadata types use basic mapping. These types were defined in Section 5.2, “Field and Property Metadata”.
			In fact, you have already seen examples of basic field mappings in 
			this chapter - the mapping of all identity fields in
			Example 12.3, “Identity Mapping”.  As you saw
			in that section, to write a basic field mapping you use the
			Column annotation to describe the column
			the field value is stored in.  We discussed the Column
			 annotation in 
			Section 12.3, “Column”.  Recall that the 
			name of the column defaults to the field name, and the type of the
			column defaults to an appropriate type for the field type.  
			These defaults allow you to sometimes omit the annotation
			altogether.
			
				Adding the Lob marker annotation to a
				basic field signals that the data is to be stored as a 
				LOB (Large OBject).  If the field holds string
				or character data, it will map to a CLOB
				(Character Large OBject) database column.  If the field holds 
				any other data type, it will be stored as binary data in a 
				BLOB (Binary Large OBject) column.  The 
				implementation will serialize the Java value if needed.
				
				The equivalent XML element is lob,
				which has no children or attributes.
				
				You can apply the Enumerated annotation
				to your Enum fields to control how they
				map to the database.  The Enumerated
				annotation's value one of the following constants from the 
				EnumType enum: 
				
						EnumType.ORDINAL: The default.
						The persistence implementation places the ordinal value
						of the enum in a numeric column.  This is an efficient 
						mapping, but may break if you rearrange the Java 
						enum declaration.  
						
						EnumType.STRING: Store the name of
						the enum value rather than the ordinal.  This mapping
						uses a VARCHAR column rather than
						a numeric one.
						
				The Enumerated annotation is 
				optional.  Any un-annotated enumeration field defaults to
				ORDINAL mapping.
				
				The corresponding XML element is enumerated.
				Its embedded text must be one of 
				STRING or ORIDINAL.
				
				The Temporal annotation determines
				how the implementation handles your basic 
				java.util.Date and 
				java.util.Calendar fields at the JDBC level.  The
				Temporal annotation's value is a
				constant from the TemporalType enum.
				Available values are:
				
						TemporalType.TIMESTAMP: The default.
						Use JDBC's timestamp APIs to manipulate the column
						data.
						
						TemporalType.DATE: Use JDBC's 
						SQL date APIs to manipulate the column data.
						
						TemporalType.TIME: Use JDBC's 
						time APIs to manipulate the column data.
						
				If the Temporal annotation is omitted,
				the implementation will treat the data as a timestamp.
				
				The corresponding XML element is temporal,
				whose text value must be one of:
				TIME, DATE, or
				TIMESTAMP.
				
				Below we present an updated diagram of our model and its 
				associated database schema, followed by the corresponding 
				mapping metadata.  Note that the mapping metadata relies on 
				defaults where possible.  Also note that as a mapped superclass,
				Document can define mappings that will 
				automatically transfer to its subclass' tables.  In 
				Section 12.8.3, “Embedded Mapping”, you will see how
				a subclass can override its mapped superclass' mappings.
				

Example 12.10. Basic Field Mapping
package org.mag;
@Entity
@IdClass(Magazine.MagazineId.class)
@Table(name="MAG")
@DiscriminatorValue("Mag")
public class Magazine
{
    @Column(length=9)
    @Id private String isbn;
    @Id private String title;
    @Column(name="VERS")
    @Version private int version;
    
    private String name;
    private double price;
    @Column(name="COPIES")
    private int copiesSold;
    ...
    public static class MagazineId
    {
        ...
    }
}
@Entity
@Table(name="ART", uniqueConstraints=@Unique(columnNames="TITLE"))
@SequenceGenerator(name="ArticleSeq", sequenceName="ART_SEQ")
public class Article
{
    @Id
    @GeneratedValue(strategy=GenerationType.SEQUENCE, generator="ArticleSeq") 
    private long id;
    @Column(name="VERS")
    @Version private int version;
    private String title;
    private byte[] content;
    ...
}
package org.mag.pub;
@Entity
@Table(name="COMP")
public class Company
{
    @Column(name="CID")
    @Id private long id;
    @Column(name="VERS")
    @Version private int version;
    private String name;
    @Column(name="REV")
    private double revenue;
    ...
}
@Entity
@Table(name="AUTH")
public class Author
{
    @Id
    @GeneratedValue(strategy=GenerationType.TABLE, generator="AuthorGen")
    @TableGenerator(name="AuthorGen", table="AUTH_GEN", pkColumnName="PK",
        valueColumnName="AID")
    @Column(name="AID", columnDefinition="INTEGER64")
    private long id;
    @Column(name="VERS")
    @Version private int version;
    @Column(name="FNAME")
    private String firstName;
    @Column(name="LNAME")
    private String lastName;
    ...
}
@Embeddable
public class Address
{
    ...
}
package org.mag.subscribe;
@MappedSuperclass
public abstract class Document
{
    @Id
    @GeneratedValue(strategy=GenerationType.IDENTITY)
    private long id;
    @Column(name="VERS")
    @Version private int version;
    ...
}
@Entity
@Table(schema="CNTRCT")
@Inheritance(strategy=InheritanceType.JOINED)
@DiscriminatorColumn(name="CTYPE")
public class Contract
    extends Document
{
    @Lob
    private String terms;
    ...
}
@Entity
@Table(name="SUB", schema="CNTRCT")
@DiscriminatorColumn(name="KIND", discriminatorType=DiscriminatorType.INTEGER)
@DiscriminatorValue("1")
public class Subscription
{
    @Id
    @GeneratedValue(strategy=GenerationType.IDENTITY)
    private long id;
    @Column(name="VERS")
    @Version private int version;
    @Column(name="START")
    private Date startDate;
    @Column(name="PAY")
    private double payment;
    ...
    @Entity
    @Table(name="LINE_ITEM", schema="CNTRCT")
    public static class LineItem
        extends Contract
    {
        @Column(name="COMM")
        private String comments;
        private double price;
        private long num;
        ...
    }
}
@Entity(name="Lifetime")
@DiscriminatorValue("2")
public class LifetimeSubscription
    extends Subscription
{
    @Basic(fetch=FetchType.LAZY)
    @Column(name="ELITE")
    private boolean getEliteClub () { ... }
    public void setEliteClub (boolean elite) { ... }
    ...
}
@Entity(name="Trial")
@DiscriminatorValue("3")
public class TrialSubscription
    extends Subscription
{
    @Column(name="END")
    public Date getEndDate () { ... }
    public void setEndDate (Date end) { ... }
    ...
}
The same metadata expressed in XML:
<entity-mappings xmlns="http://java.sun.com/xml/ns/persistence/orm" 
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
    xsi:schemaLocation="http://java.sun.com/xml/ns/persistence/orm orm_1_0.xsd"
    version="1.0">
    <mapped-superclass class="org.mag.subscribe.Document">
        <attributes>
            <id name="id">
                <generated-value strategy="IDENTITY"/>
            </id>
            <version name="version">
                <column name="VERS"/>
            </version>
            ...
        </attributes>
    </mapped-superclass>
    <entity class="org.mag.Magazine">
        <table name="MAG"/>
        <id-class="org.mag.Magazine.MagazineId"/>
        <discriminator-value>Mag</discriminator-value>
        <attributes>
            <id name="isbn">
                <column length="9"/>
            </id>
            <id name="title"/>
            <basic name="name"/>
            <basic name="price"/>
            <basic name="copiesSold">
                <column name="COPIES"/>
            </basic>
            <version name="version">
                <column name="VERS"/>
            </version>
            ...
        </attributes>
    </entity>
    <entity class="org.mag.Article">
        <table name="ART">
            <unique-constraint>
               <column-name>TITLE</column-name>
            </unique-constraint>
        </table>
        <sequence-generator name="ArticleSeq", sequenceName="ART_SEQ"/>
        <attributes>
            <id name="id">
                <generated-value strategy="SEQUENCE" generator="ArticleSeq"/>
            </id>
            <basic name="title"/>
            <basic name="content"/>
            <version name="version">
                <column name="VERS"/>
            </version>
            ...
        </attributes>
    </entity>
    <entity class="org.mag.pub.Company">
        <table name="COMP"/>
        <attributes>
            <id name="id">
                <column name="CID"/>
            </id>
            <basic name="name"/>
            <basic name="revenue">
                <column name="REV"/>
            </basic>
        </attributes>
    </entity>
    <entity class="org.mag.pub.Author">
        <table name="AUTH"/>
        <attributes>
            <id name="id">
                <column name="AID" column-definition="INTEGER64"/>
                <generated-value strategy="TABLE" generator="AuthorGen"/>
                <table-generator name="AuthorGen" table="AUTH_GEN" 
                    pk-column-name="PK" value-column-name="AID"/>
            </id>
            <basic name="firstName">
                <column name="FNAME"/>
            </basic>
            <basic name="lastName">
                <column name="LNAME"/>
            </basic>
            <version name="version">
                <column name="VERS"/>
            </version>
            ...
        </attributes>
    </entity>
    <entity class="org.mag.subcribe.Contract">
        <table schema="CNTRCT"/>
        <inheritance strategy="JOINED"/>
        <discriminator-column name="CTYPE"/>
        <attributes>
            <basic name="terms">
                <lob/>
            </basic>
            ...
        </attributes>
    </entity>
    <entity class="org.mag.subcribe.Subscription">
        <table name="SUB" schema="CNTRCT"/>
        <inheritance strategy="SINGLE_TABLE"/>
        <discriminator-value>1</discriminator-value>
        <discriminator-column name="KIND" discriminator-type="INTEGER"/>
        <attributes>
            <id name="id">
                <generated-value strategy="IDENTITY"/>
            </id>
            <basic name="payment">
                <column name="PAY"/>
            </basic>
            <basic name="startDate">
                <column name="START"/>
            </basic>
            <version name="version">
                <column name="VERS"/>
            </version>
            ...
        </attributes>
    </entity>
    <entity class="org.mag.subscribe.Subscription.LineItem">
        <table name="LINE_ITEM" schema="CNTRCT"/>
        <primary-key-join-column name="ID" referenced-column-name="PK"/>
        <attributes>
            <basic name="comments">
                <column name="COMM"/>
            </basic>
            <basic name="price"/>
            <basic name="num"/>
            ...
        </attributes>
    </entity>
    <entity class="org.mag.subscribe.LifetimeSubscription" name="Lifetime">
        <discriminator-value>2</discriminator-value>
        <attributes>
            <basic name="eliteClub" fetch="LAZY">
                <column name="ELITE"/>
            </basic>
            ...
        </attributes>
    </entity>
    <entity class="org.mag.subscribe.TrialSubscription" name="Trial">
        <discriminator-value>3</discriminator-value>
        <attributes>
            <basic name="endDate">
                <column name="END"/>
            </basic>
            ...
        </attributes>
    </entity>
</entity-mappings>
Sometimes a a logical record is spread over multiple database tables. EJB persistence calls a class' declared table the primary table, and calls other tables that make up a logical record secondary tables. You can map any persistent field to a secondary table. Just write the standard field mapping, then perform these two additional steps:
					Set the table attribute of each
					of the field's columns or join columns to the name of the 
					secondary table.
					
Define the secondary table on the entity class declaration.
			You define secondary tables with the SecondaryTable
			 annotation.  This annotation has all the properties
			of the Table annotation covered in
			Section 12.1, “Table”, plus a 
			pkJoinColumns property.
			
			The pkJoinColumns property is an array of 
			PrimaryKeyJoinColumns dictating how to join 
			secondary table records to their owning primary table records.  Each
			PrimaryKeyJoinColumn joins a secondary table
			column to a primary key column in the primary table.  See
			Section 12.6.2, “Joined” above for 
			coverage of PrimaryKeyJoinColumn's 
			properties.
			
			The corresponding XML element 
			is secondary-table.  This element has all
			the attributes of the table element, but also 
			accepts nested primary-key-join-column elements.
			
			In the following example, we move the Article.content
			 field we mapped in 
			Section 12.8.1, “Basic Mapping” into a joined 
			secondary table, like so:
			

Example 12.11. Secondary Table Field Mapping
package org.mag;
@Entity
@Table(name="ART")
@SecondaryTable(name="ART_DATA", 
    pkJoinColumns=@PrimaryKeyJoinColumn(name="ART_ID", referencedColumnName="ID"))
public class Article
{
    @Id private long id;
    @Column(table="ART_DATA")
    private byte[] content;
    ...
}
And in XML:
<entity class="org.mag.Article">
    <table name="ART">
    <secondary-table name="ART_DATA">
        <primary-key-join-column name="ART_ID" referenced-column-name="ID"/>
    </secondary-table>
    <attributes>
        <id name="id"/>
        <basic name="content">
            <column table="ART_DATA"/>
        </basic>
        ...
    </attributes>
</entity>
Chapter 5, Metadata describes EJB's concept of embeddable objects. The field values of embedded objects are stored as part of the owning record, rather than as a separate database record. Thus, instead of mapping a relation to an embeddable object as a foreign key, you map all the fields of the embeddable instance to columns in the owning field's table.

			EJB persistence defaults the embedded column names and descriptions
			to those of the embeddable class' field mappings.  The 
			AttributeOverride annotation overrides a basic embedded
			mapping. This annotation has the following properties:
			
					String name: The name of the 
					embedded class' field being mapped to this class' table.
					
					Column column: The column defining the 
					mapping of the embedded class' field to this class' 
					table.
					
			The corresponding XML element is 
			attribute-override.  It has a single name
			 attribute to name the field being overridden,
			and a single column child element.
			
			To declare multiple overrides, use the AttributeOverrides
			 annotation, whose value is an array of 
			AttributeOverrides.  In XML, simply list 
			multiple attribute-override elements in 
			succession.
			
			To override a many to one or one to one relationship, use the
			AssociationOverride annotation in place of
			AttributeOverride.  
			AssociationOverride has the following properties:
			
					String name: The name of the 
					embedded class' field being mapped to this class' table.
					
					JoinColumn[] joinColumns: The foreign key
					columns joining to the related record.
					
			The corresponding XML element is 
			association-override.  It has a single name
			 attribute to name the field being overridden,
			and one or more join-column child elements.
			
			To declare multiple relation overrides, use the 
			AssociationOverrides annotation, whose value is an 
			array of AssociationOverrides.  In XML, 
			simply list multiple association-override 
			elements in succession.
			
Example 12.12. Embedded Field Mapping
				In this example, Company overrides the
				default mapping of Address.street and
				Address.city.
				All other embedded mappings are taken from the 
				Address embeddable class.
				
package org.mag.pub;
@Entity
@Table(name="COMP")
public class Company
{
    @Embedded
    @AttributeOverrides({
        @AttributeOverride(name="street", column=@Column(name="STRT")),
        @AttributeOverride(name="city", column=@Column(name="ACITY"))
    })
    private Address address;
    
    ...
}
@Entity
@Table(name="AUTH")
public class Author
{
    // use all defaults from Address class mappings
    private Address address;
    
    ...
}
@Embeddable
public class Address
{
    private String street;
    private String city;
    @Column(columnDefinition="CHAR(2)")
    private String state;
    private String zip;
}
The same metadata expressed in XML:
<entity class="org.mag.pub.Company">
    <table name="COMP"/>
    <attributes>
        ...
        <embedded name="address">
            <attribute-override name="street">
               <column name="STRT"/>
            </attribute-override>
            <attribute-override name="city">
               <column name="ACITY"/>
            </attribute-override>
        </embedded>
    </attributes>
</entity>
<entity class="org.mag.pub.Author">
    <table name="AUTH"/>
    <attributes>
        <embedded name="address">
            <!-- use all defaults from Address -->
        </embedded>
    </attributes>
</entity>
<embeddable class="org.mag.pub.Address">
    <attributes>
        <basic name="street"/>
        <basic name="city"/>
        <basic name="state">
            <column column-definition="CHAR(2)"/>
        </basic>
        <basic name="zip"/>
    </attributes>
</embeddable>
			You can also use attribute overrides on an entity class to 
			override mappings defined by
			its mapped superclass or table-per-class superclass.  The example 
			below re-maps the Document.version field to the 
			Contract table's CVERSION
			column.
			
Example 12.13. Mapping Mapped Superclass Field
@MappedSuperclass
public abstract class Document
{
    @Column(name="VERS")
    @Version private int version;
    ...
}
@Entity
@Table(schema="CNTRCT")
@Inheritance(strategy=InheritanceType.JOINED)
@DiscriminatorColumn(name="CTYPE")
@AttributeOverride(name="version", column=@Column(name="CVERSION"))
public class Contract
    extends Document
{
    ...
}
The same metadata expressed in XML form:
<mapped-superclass class="org.mag.subcribe.Document">
    <attributes>
        <version name="version">
            <column name="VERS">
        </version>
        ...
    </attributes>
</mapped-superclass>
<entity class="org.mag.subcribe.Contract">
    <table schema="CNTRCT"/>
    <inheritance strategy="JOINED"/>
    <discriminator-column name="CTYPE"/>
    <attribute-override name="version">
        <column name="CVERSION"/>
    </attribute-override>
    <attributes>
        ...
    </attributes>
</entity>
			A direct relation is a non-embedded persistent field that holds a 
			reference to another entity.
			many to one and 
			one to one 
			metadata field types are mapped as direct
			relations.  Our model has three direct relations: 
			Magazine's publisher 
			field is a direct relation to a Company, 
			Magazine's coverArticle 
			field is a direct relation to Article, and 
			the LineItem.magazine field is a direct relation
			to a Magazine.  Direct relations are 
			represented in the database by foreign key columns:
			

			You typically map a direct relation with 
			JoinColumn annotations describing how the 
			local foreign key columns join to the primary key columns of the 
			related record.  The JoinColumn annotation 
			exposes the following properties:
			
					String name: The name of the foreign key
					column.  Defaults to the relation field name, plus an
					underscore, plus the name of the referenced primary key 
					column.
					
					String referencedColumnName: The name 
					of the primary key column being joined to.  If there is 
					only one identity field in the related entity class, the 
					join column name defaults to the name of the identity 
					field's column.
					
					boolean unique: Whether this column
					is guaranteed to hold unique values for all rows.  Defaults
					to false.
					
			JoinColumn also has the same 
			nullable, insertable, 
			updatable, columnDefinition, and
			table properties as the 
			Column annotation.  See 
			Section 12.3, “Column” for details on these
			properties.
			
			The join-column element represents a join column
			in XML.  Its attributes mirror the above annotation's properties:
			
name
referenced-column-name
unique
nullable
insertable
updatable
column-definition
table
			When there are multiple columns involved in the join, as when a 
			LineItem references a Magazine
			 in our model, the JoinColumns 
			annotation allows you to specify an array of JoinColumn
			 values.  In XML, simply list multiple
			join-column elements.
			
| ![[Note]](img/note.gif) | Note | 
|---|---|
| Kodo supports many non-standard joins. See Section 7.6, “Non-Standard Joins” in the Reference Guide for details. | 
Example 12.14. Direct Relation Field Mapping
package org.mag;
@Table(name="AUTH")
public class Magazine
{
    @Column(length=9)
    @Id private String isbn;
    @Id private String title;
    @OneToOne
    @JoinColumn(name="COVER_ID" referencedColumnName="ID")
    private Article coverArticle;
    @ManyToOne
    @JoinColumn(name="PUB_ID" referencedColumnName="CID")
    private Company publisher;
    ...
}
@Table(name="ART")
public class Article
{
    @Id private long id;
    ...
}
package org.mag.pub;
@Table(name="COMP")
public class Company
{
    @Column(name="CID")
    @Id private long id;
    ...
}
package org.mag.subscribe;
public class Subscription
{
    ...
    @Table(name="LINE_ITEM", schema="CNTRCT")
    public static class LineItem
        extends Contract
    {
        @ManyToOne
        @JoinColumns({
            @JoinColumn(name="MAG_ISBN" referencedColumnName="ISBN"),
            @JoinColumn(name="MAG_TITLE" referencedColumnName="TITLE")
        })
        private Magazine magazine;
        ...
    }
}
The same metadata expressed in XML form:
<entity class="org.mag.Magazine">
    <table name="MAG"/>
    <id-class="org.mag.Magazine.MagazineId"/>
    <attributes>
        <id name="isbn">
            <column length="9"/>
        </id>
        <id name="title"/>
        <one-to-one name="coverArticle">
            <join-column name="COVER_ID" referenced-column-name="ID"/>
        </one-to-one>
        <many-to-one name="publisher">
            <join-column name="PUB_IC" referenced-column-name="CID"/>
        </many-to-one>
        ...
    </attributes>
</entity>
<entity class="org.mag.Article">
    <table name="ART"/>
    <attributes>
        <id name="id"/>
        ...
    </attributes>
</entity>
<entity class="org.mag.pub.Company">
    <table name="COMP"/>
    <attributes>
        <id name="id">
            <column name="CID"/>
        </id>
        ...
    </attributes>
</entity>
<entity class="org.mag.subscribe.Subscription.LineItem">
    <table name="LINE_ITEM" schema="CNTRCT"/>
    <primary-key-join-column name="ID" referenced-column-name="PK"/>
    <attributes>
        <many-to-one name="magazine">
            <join-column name="MAG_ISBN" referenced-column-name="ISBN"/>
            <join-column name="MAG_TITLE" referenced-column-name="TITLE"/>
        </many-to-one>
        ...
    </attributes>
</entity>
			When the entities in a one to one relation join on
			shared primary key values rather than separate foreign key columns, 
			use the PrimaryKeyJoinColumn(s) 
			annotation or primary-key-join-column elements 
			in place of JoinColumn(s) / 
			join-column elements.
			
A join table consists of two foreign keys. Each row of a join table associates two objects together. EJB persistence uses join tables to represent collections of entity objects: one foreign key refers back to the collection's owner, and the other refers to a collection element.
			one to many and 
			many to many
			metadata field types can map to join 
			tables.  Several fields in our model use join table mappings,
			including Magazine.articles and 
			Article.authors.
			

			You define join tables with the JoinTable 
			annotation.  This annotation has the following properties: 
			
					String name: Table name.  If not 
					given, the name of the table defaults to the name of the
					owning entity's table, plus an underscore, plus the name of
					the related entity's table.
					
					String catalog: Table catalog.
					
String schema: Table schema.
					JoinColumn[] joinColumns: Array
					of JoinColumn sshowing how to
					associate join table records with the owning row in the
					primary table.  This property mirrors the
					pkJoinColumns property of the 
					SecondaryTable annotation in functionality.
					See Section 12.8.2, “Secondary Tables” to
					refresh your memory on secondary tables.
					
If this is a bidirectional relation (see Section 5.2.9.1, “Bidirectional Relations”), the name of a join column defaults to the inverse field name, plus an underscore, plus the referenced primary key column name. Otherwise, the join column name defaults to the field's owning entity name, plus an underscore, plus the referenced primary key column name.
					JoinColumn[] inverseJoinColumns: Array
					of JoinColumns showing how to
					associate join table records with the records that form the
					elements of the collection.  These join columns are used
					just like the join columns for direct relations, and they
					have the same naming defaults.
					Read Section 12.8.4, “Direct Relations” for a 
					review of direct relation mapping.
					
			join-table is the corresponding XML element.
			It has the same attributes as the table
			element, but includes the ability to nest 
			join-column and 
			inverse-join-column elements as children.
			We have seen join-column elements already;
			inverse-join-column elements have the same
			attributes.
			
Here are the join table mappings for the diagram above.
Example 12.15. Join Table Mapping
package org.mag;
@Entity
@Table(name="MAG")
public class Magazine
{
    @Column(length=9)
    @Id private String isbn;
    @Id private String title;
    @OneToMany(...)
    @OrderBy
    @JoinTable(name="MAG_ARTS",
        joinColumns={
            @JoinColumn(name="MAG_ISBN", referencedColumnName="ISBN"),
            @JoinColumn(name="MAG_TITLE", referencedColumnName="TITLE")
        },
        inverseJoinColumns=@JoinColumn(name="ART_ID", referencedColumnName="ID"))
    private Collection<Article> articles;
    ...
}
@Entity
@Table(name="ART")
public class Article
{
    @Id private long id;
    @ManyToMany(cascade=CascadeType.PERSIST)
    @OrderBy("lastName, firstName")
    @JoinTable(name="ART_AUTHS",
        joinColumns=@JoinColumn(name="ART_ID", referencedColumnName="ID"),
        inverseJoinColumns=@JoinColumn(name="AUTH_ID", referencedColumnName="AID"))
    private Collection<Author> authors;
    ...
}
package org.mag.pub;
@Entity
@Table(name="AUTH")
public class Author
{
    @Column(name="AID", columnDefinition="INTEGER64")
    @Id private long id;
    ...
}
The same metadata expressed in XML:
<entity class="org.mag.Magazine">
    <table name="MAG"/>
    <attributes>
        <id name="isbn">
            <column length="9"/>
        </id>
        <id name="title"/>
        <one-to-many name="articles">
            <order-by/>
            <join-table name="MAG_ARTS">
                <join-column name="MAG_ISBN" referenced-column-name="ISBN"/>
                <join-column name="MAG_TITLE" referenced-column-name="TITLE"/>
            </join-table>
        </one-to-many>
        ...
    </attributes>
</entity>
<entity class="org.mag.Article">
    <table name="ART"/>
        <attributes>
            <id name="id"/>
            <many-to-many name="articles">
                <order-by>lastName, firstName</order-by>
                <join-table name="ART_AUTHS">
                    <join-column name="ART_ID" referenced-column-name="ID"/>
                    <inverse-join-column name="AUTH_ID" referenced-column-name="AID"/>
                </join-table>
            </many-to-many>
            ...
       </attributes>
</entity>
<entity class="org.mag.pub.Author">
    <table name="AUTH"/>
    <attributes>
        <id name="id">
            <column name="AID" column-definition="INTEGER64"/>
        </id>
        ...
    </attributes>
</entity>
		Section 5.2.9.1, “Bidirectional Relations” introduced 
		bidirectional relations.  To map a bidirectional relation, you map 
		one field normally using the annotations we have covered throughout 
		this chapter.  Then you use the mappedBy property
		of the other field's metadata annotation or the corresponding 
		mapped-by XML attribute to refer to the mapped 
		field.  Look for this pattern in these bidirectional relations as
		you peruse the complete mappings below:
		
				Magazine.publisher and 
				Company.ags.
				
				Article.authors and 
				Author.articles.
				
		All map fields in EJB persistence are modeled on either
		one to many or many to many associations.  The map key is always 
		derived from an associated
		entity's field.  Thus map fields use the same mappings as any
		one to many or many to many fields, namely dedicated 
		join tables 
		or bidirectional 
		relations.  The only additions are the MapKey
		 annotation and map-key element to 
		declare the key field.  We covered these additions in
		in Section 5.2.13, “Map Key”.
		

		The example below maps Subscription's map of
		LineItems to the SUB_ITEMS
		join table.  The key for each map entry is the 
		LineItem's num field value.
		
Example 12.16. Join Table Map Mapping
package org.mag.subscribe;
@Entity
@Table(name="SUB", schema="CNTRCT")
public class Subscription
{
@OneToMany(cascade={CascadeType.PERSIST,CascadeType.REMOVE})
@MapKey(name="num")
@JoinTable(name="SUB_ITEMS", schema="CNTRCT",
    joinColumns=@JoinColumn(name="SUB_ID"),
    inverseJoinColumns=@JoinColumn(name="ITEM_ID"))
private Map<Long,LineItem> items;
...
@Entity
@Table(name="LINE_ITEM", schema="CNTRCT")
public static class LineItem
    extends Contract
{
    private long num;
    ...
}
}
The same metadata expressed in XML:
<entity class="org.mag.subscribe.Subscription">
    <table name="SUB" schema="CNTRCT"/>
    <attributes>
        ...
        <one-to-many name="items">
            <map-key name="num">
            <join-table name="MAG_ARTS">
                <join-column name="MAG_ISBN" referenced-column-name="ISBN"/>
                <join-column name="MAG_TITLE" referenced-column-name="TITLE"/>
            </join-table>
            <cascade>
                <cascade-persist/>
                <cascade-remove/>
            </cascade>
        </one-to-many>
        ...
    </attributes>
</entity>
<entity class="org.mag.subscribe.Subscription.LineItem">
    <table name="LINE_ITEM" schema="CNTRCT"/>
    <attributes>
        ...
        <basic name="num"/>
        ...
    </attributes>
</entity>
|    |