blob: 4e29274d82c71796f2f5e0bb70d4d6f146bd2bbf [file] [log] [blame]
<html><head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>9.&nbsp; The Complete Mappings</title><base href="display"><link rel="stylesheet" type="text/css" href="css/docbook.css"><meta name="generator" content="DocBook XSL-NS Stylesheets V1.76.1"><link rel="home" href="manual.html" title="Apache OpenJPA 2.4 User's Guide"><link rel="up" href="jpa_overview_mapping.html" title="Chapter&nbsp;13.&nbsp; Mapping Metadata"><link rel="prev" href="jpa_overview_mapping_field.html" title="8.&nbsp; Field Mapping"><link rel="next" href="jpa_overview_conclusion.html" title="Chapter&nbsp;14.&nbsp; Conclusion"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">9.&nbsp;
The Complete Mappings
</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="jpa_overview_mapping_field.html">Prev</a>&nbsp;</td><th width="60%" align="center">Chapter&nbsp;13.&nbsp;
Mapping Metadata
</th><td width="20%" align="right">&nbsp;<a accesskey="n" href="jpa_overview_conclusion.html">Next</a></td></tr></table><hr></div><div class="section" title="9.&nbsp; The Complete Mappings"><div class="titlepage"><div><div><h2 class="title" style="clear: both" id="jpa_overview_mapping_full">9.&nbsp;
The Complete Mappings
</h2></div></div></div>
<p>
We began this chapter with the goal of mapping the following object model:
</p>
<div class="mediaobject"><table border="0" summary="manufactured viewport for HTML img" cellspacing="0" cellpadding="0" width="369"><tr><td><img src="img/jpa-meta-model.png"></td></tr></table></div>
<p>
That goal has now been met. In the course of explaining JPA's object-relational
mapping metadata, we slowly built the requisite schema and mappings for the
complete model. First, the database schema:
</p>
<div class="mediaobject"><table border="0" summary="manufactured viewport for HTML img" cellspacing="0" cellpadding="0" width="326"><tr><td><img src="img/jpa-data-model.png"></td></tr></table></div>
<p>
And finally, the complete entity mappings. We have trimmed the mappings to take
advantage of JPA defaults where possible.
</p>
<div class="example"><a name="jpa_overview_mapping_fullex"></a><p class="title"><b>Example&nbsp;13.17.&nbsp;
Full Entity Mappings
</b></p><div class="example-contents">
<pre class="programlisting">
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;
@OneToOne(fetch=FetchType.LAZY,
cascade={CascadeType.PERSIST,CascadeType.REMOVE})
@JoinColumn(name="COVER_ID")
private Article coverArticle;
@OneToMany(cascade={CascadeType.PERSIST,CascadeType.REMOVE})
@OrderBy
@JoinTable(name="MAG_ARTS",
joinColumns={
@JoinColumn(name="MAG_ISBN", referencedColumnName="ISBN"),
@JoinColumn(name="MAG_TITLE", referencedColumnName="TITLE")
},
inverseJoinColumns=@JoinColumn(name="ART_ID"))
private Collection&lt;Article&gt; articles;
@ManyToOne(fetch=FetchType.LAZY, cascade=CascadeType.PERSIST)
@JoinColumn(name="PUB_ID")
private Company publisher;
@Transient private byte[] data;
...
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;
@ManyToMany(cascade=CascadeType.PERSIST)
@OrderBy("lastName, firstName")
@JoinTable(name="ART_AUTHS",
joinColumns=@JoinColumn(name="ART_ID"),
inverseJoinColumns=@JoinColumn(name="AUTH_ID"))
private Collection&lt;Author&gt; authors;
...
}
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;
@Embedded
@AttributeOverrides({
@AttributeOverride(name="street", column=@Column(name="STRT")),
@AttributeOverride(name="city", column=@Column(name="ACITY"))
})
private Address address;
@OneToMany(mappedBy="publisher", cascade=CascadeType.PERSIST)
private Collection&lt;Magazine&gt; mags;
@OneToMany(cascade=CascadeType.PERSIST,CascadeType.REMOVE)
@JoinTable(name="COMP_SUBS",
joinColumns=@JoinColumn(name="COMP_ID"),
inverseJoinColumns=@JoinColumn(name="SUB_ID"))
private Collection&lt;Subscription&gt; subscriptions;
...
}
@Entity
@Table(name="AUTH")
public class Author {
@Id
@GeneratedValue(strategy=GenerationType.TABLE, generator="AuthorGen")
@TableGenerator(name="AuthorGen", tableName="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;
private Address address;
@ManyToMany(mappedBy="authors", cascade=CascadeType.PERSIST)
private Collection&lt;Article&gt; arts;
...
}
@Embeddable
public class Address {
private String street;
private String city;
@Column(columnDefinition="CHAR(2)")
private String state;
private String zip;
}
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;
@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&lt;Long,LineItem&gt; items;
...
@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;
@ManyToOne
@JoinColumns({
@JoinColumn(name="MAG_ISBN", referencedColumnName="ISBN"),
@JoinColumn(name="MAG_TITLE", referencedColumnName="TITLE")
})
private Magazine magazine;
...
}
}
@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) { ... }
...
}
</pre>
<p>
The same metadata expressed in XML form:
</p>
<pre class="programlisting">
&lt;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"&gt;
&lt;mapped-superclass class="org.mag.subscribe.Document"&gt;
&lt;attributes&gt;
&lt;id name="id"&gt;
&lt;generated-value strategy="IDENTITY"/&gt;
&lt;/id&gt;
&lt;version name="version"&gt;
&lt;column name="VERS"/&gt;
&lt;/version&gt;
&lt;/attributes&gt;
&lt;/mapped-superclass&gt;
&lt;entity class="org.mag.Magazine"&gt;
&lt;table name="MAG"/&gt;
&lt;id-class="org.mag.Magazine.MagazineId"/&gt;
&lt;discriminator-value&gt;Mag&lt;/discriminator-value&gt;
&lt;attributes&gt;
&lt;id name="isbn"&gt;
&lt;column length="9"/&gt;
&lt;/id&gt;
&lt;id name="title"/&gt;
&lt;basic name="name"/&gt;
&lt;basic name="price"/&gt;
&lt;basic name="copiesSold"&gt;
&lt;column name="COPIES"/&gt;
&lt;/basic&gt;
&lt;version name="version"&gt;
&lt;column name="VERS"/&gt;
&lt;/version&gt;
&lt;many-to-one name="publisher" fetch="LAZY"&gt;
&lt;join-column name="PUB_ID"/&gt;
&lt;cascade&gt;
&lt;cascade-persist/&gt;
&lt;/cascade&gt;
&lt;/many-to-one&gt;
&lt;one-to-many name="articles"&gt;
&lt;order-by/&gt;
&lt;join-table name="MAG_ARTS"&gt;
&lt;join-column name="MAG_ISBN" referenced-column-name="ISBN"/&gt;
&lt;join-column name="MAG_TITLE" referenced-column-name="TITLE"/&gt;
&lt;inverse-join-column name="ART_ID"/&gt;
&lt;/join-table&gt;
&lt;cascade&gt;
&lt;cascade-persist/&gt;
&lt;cascade-remove/&gt;
&lt;/cascade&gt;
&lt;/one-to-many&gt;
&lt;one-to-one name="coverArticle" fetch="LAZY"&gt;
&lt;join-column name="COVER_ID"/&gt;
&lt;cascade&gt;
&lt;cascade-persist/&gt;
&lt;cascade-remove/&gt;
&lt;/cascade&gt;
&lt;/one-to-one&gt;
&lt;transient name="data"/&gt;
&lt;/attributes&gt;
&lt;/entity&gt;
&lt;entity class="org.mag.Article"&gt;
&lt;table name="ART"&gt;
&lt;unique-constraint&gt;
&lt;column-name&gt;TITLE&lt;/column-name&gt;
&lt;/unique-constraint&gt;
&lt;/table&gt;
&lt;sequence-generator name="ArticleSeq", sequenceName="ART_SEQ"/&gt;
&lt;attributes&gt;
&lt;id name="id"&gt;
&lt;generated-value strategy="SEQUENCE" generator="ArticleSeq"/&gt;
&lt;/id&gt;
&lt;basic name="title"/&gt;
&lt;basic name="content"/&gt;
&lt;version name="version"&gt;
&lt;column name="VERS"/&gt;
&lt;/version&gt;
&lt;many-to-many name="articles"&gt;
&lt;order-by&gt;lastName, firstName&lt;/order-by&gt;
&lt;join-table name="ART_AUTHS"&gt;
&lt;join-column name="ART_ID" referenced-column-name="ID"/&gt;
&lt;inverse-join-column name="AUTH_ID" referenced-column-name="AID"/&gt;
&lt;/join-table&gt;
&lt;/many-to-many&gt;
&lt;/attributes&gt;
&lt;/entity&gt;
&lt;entity class="org.mag.pub.Company"&gt;
&lt;table name="COMP"/&gt;
&lt;attributes&gt;
&lt;id name="id"&gt;
&lt;column name="CID"/&gt;
&lt;/id&gt;
&lt;basic name="name"/&gt;
&lt;basic name="revenue"&gt;
&lt;column name="REV"/&gt;
&lt;/basic&gt;
&lt;version name="version"&gt;
&lt;column name="VERS"/&gt;
&lt;/version&gt;
&lt;one-to-many name="mags" mapped-by="publisher"&gt;
&lt;cascade&gt;
&lt;cascade-persist/&gt;
&lt;/cascade&gt;
&lt;/one-to-many&gt;
&lt;one-to-many name="subscriptions"&gt;
&lt;join-table name="COMP_SUBS"&gt;
&lt;join-column name="COMP_ID"/&gt;
&lt;inverse-join-column name="SUB_ID"/&gt;
&lt;/join-table&gt;
&lt;cascade&gt;
&lt;cascade-persist/&gt;
&lt;cascade-remove/&gt;
&lt;/cascade&gt;
&lt;/one-to-many&gt;
&lt;embedded name="address"&gt;
&lt;attribute-override name="street"&gt;
&lt;column name="STRT"/&gt;
&lt;/attribute-override&gt;
&lt;attribute-override name="city"&gt;
&lt;column name="ACITY"/&gt;
&lt;/attribute-override&gt;
&lt;/embedded&gt;
&lt;/attributes&gt;
&lt;/entity&gt;
&lt;entity class="org.mag.pub.Author"&gt;
&lt;table name="AUTH"/&gt;
&lt;attributes&gt;
&lt;id name="id"&gt;
&lt;column name="AID" column-definition="INTEGER64"/&gt;
&lt;generated-value strategy="TABLE" generator="AuthorGen"/&gt;
&lt;table-generator name="AuthorGen" table="AUTH_GEN"
pk-column-name="PK" value-column-name="AID"/&gt;
&lt;/id&gt;
&lt;basic name="firstName"&gt;
&lt;column name="FNAME"/&gt;
&lt;/basic&gt;
&lt;basic name="lastName"&gt;
&lt;column name="LNAME"/&gt;
&lt;/basic&gt;
&lt;version name="version"&gt;
&lt;column name="VERS"/&gt;
&lt;/version&gt;
&lt;many-to-many name="arts" mapped-by="authors"&gt;
&lt;cascade&gt;
&lt;cascade-persist/&gt;
&lt;/cascade&gt;
&lt;/many-to-many&gt;
&lt;embedded name="address"/&gt;
&lt;/attributes&gt;
&lt;/entity&gt;
&lt;entity class="org.mag.subcribe.Contract"&gt;
&lt;table schema="CNTRCT"/&gt;
&lt;inheritance strategy="JOINED"/&gt;
&lt;discriminator-column name="CTYPE"/&gt;
&lt;attributes&gt;
&lt;basic name="terms"&gt;
&lt;lob/&gt;
&lt;/basic&gt;
&lt;/attributes&gt;
&lt;/entity&gt;
&lt;entity class="org.mag.subcribe.Subscription"&gt;
&lt;table name="SUB" schema="CNTRCT"/&gt;
&lt;inheritance strategy="SINGLE_TABLE"/&gt;
&lt;discriminator-value&gt;1&lt;/discriminator-value&gt;
&lt;discriminator-column name="KIND" discriminator-type="INTEGER"/&gt;
&lt;attributes&gt;
&lt;id name="id"&gt;
&lt;generated-value strategy="IDENTITY"/&gt;
&lt;/id&gt;
&lt;basic name="payment"&gt;
&lt;column name="PAY"/&gt;
&lt;/basic&gt;
&lt;basic name="startDate"&gt;
&lt;column name="START"/&gt;
&lt;/basic&gt;
&lt;version name="version"&gt;
&lt;column name="VERS"/&gt;
&lt;/version&gt;
&lt;one-to-many name="items"&gt;
&lt;map-key name="num"&gt;
&lt;join-table name="SUB_ITEMS" schema="CNTRCT"&gt;
&lt;join-column name="SUB_ID"/&gt;
&lt;inverse-join-column name="ITEM_ID"/&gt;
&lt;/join-table&gt;
&lt;cascade&gt;
&lt;cascade-persist/&gt;
&lt;cascade-remove/&gt;
&lt;/cascade&gt;
&lt;/one-to-many&gt;
&lt;/attributes&gt;
&lt;/entity&gt;
&lt;entity class="org.mag.subscribe.Subscription.LineItem"&gt;
&lt;table name="LINE_ITEM" schema="CNTRCT"/&gt;
&lt;attributes&gt;
&lt;basic name="comments"&gt;
&lt;column name="COMM"/&gt;
&lt;/basic&gt;
&lt;basic name="price"/&gt;
&lt;basic name="num"/&gt;
&lt;many-to-one name="magazine"&gt;
&lt;join-column name="MAG_ISBN" referenced-column-name="ISBN"/&gt;
&lt;join-column name="MAG_TITLE" referenced-column-name="TITLE"/&gt;
&lt;/many-to-one&gt;
&lt;/attributes&gt;
&lt;/entity&gt;
&lt;entity class="org.mag.subscribe.LifetimeSubscription" name="Lifetime"&gt;
&lt;discriminator-value&gt;2&lt;/discriminator-value&gt;
&lt;attributes&gt;
&lt;basic name="eliteClub" fetch="LAZY"&gt;
&lt;column name="ELITE"/&gt;
&lt;/basic&gt;
&lt;/attributes&gt;
&lt;/entity&gt;
&lt;entity class="org.mag.subscribe.TrialSubscription" name="Trial"&gt;
&lt;discriminator-value&gt;3&lt;/discriminator-value&gt;
&lt;attributes&gt;
&lt;basic name="endDate"&gt;
&lt;column name="END"/&gt;
&lt;/basic&gt;
&lt;/attributes&gt;
&lt;/entity&gt;
&lt;embeddable class="org.mag.pub.Address"&gt;
&lt;attributes&gt;
&lt;basic name="street"/&gt;
&lt;basic name="city"/&gt;
&lt;basic name="state"&gt;
&lt;column column-definition="CHAR(2)"/&gt;
&lt;/basic&gt;
&lt;basic name="zip"/&gt;
&lt;/attributes&gt;
&lt;/embeddable&gt;
&lt;/entity-mappings&gt;
</pre>
</div></div><br class="example-break">
</div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="jpa_overview_mapping_field.html">Prev</a>&nbsp;</td><td width="20%" align="center"><a accesskey="u" href="jpa_overview_mapping.html">Up</a></td><td width="40%" align="right">&nbsp;<a accesskey="n" href="jpa_overview_conclusion.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">8.&nbsp;
Field Mapping
&nbsp;</td><td width="20%" align="center"><a accesskey="h" href="manual.html">Home</a></td><td width="40%" align="right" valign="top">&nbsp;Chapter&nbsp;14.&nbsp;
Conclusion
</td></tr></table></div></body></html>