<document>
<localtoc/>

- See Basic tutorial for a complete single-table example.
- See Many-to-one tutorial for basic relations.

1. Expected SQL for the database
2. Entity bean implementation
3. Servlet loading, querying, and persisting
4. persistence.xml configuration
5. resin-web.xml configuration

create table HOUSE ( id integer auto_increment, name varchar(255) ) package demo; import javax.persistence.*; @Entity public class House { @Id @Column(name="id") @GeneratedValue private int _id; @Basic @Column(name="name") private String _name; } package demo; import javax.ejb.*; import javax.servlet.*; import javax.persistence.*; public class HouseServlet extends GenericServlet { @PersistenceUnit("test") EntityManagerFactory _factory; public void load(PrintWriter out) { EntityManager amber = _factory.createEntityManager(); try { House house = amber.find(House.class, 1); out.println("House: " + house); } finally { amber.close(); } } public void query(PrintWriter out) { EntityManager amber = _factory.createEntityManager(); try { Query query = amber.createQuery("select o from House o WHERE o.id=1"); out.println("House: " + query.getSingleResult()); } finally { amber.close(); } } @TransactionAttribute protected void insert(PrintWriter out) { EntityManager amber = _factory.createEntityManager(); try { House house = new House("Gryffindor"); amber.persist(house); } finally { amber.close(); } } } <persistence xmlns="http://java.sun.com/xml/ns/persistence" version="1.0"> <persistence-unit name="test"> </persistence-unit> </persistence> <web-app xmlns="http://caucho.com/ns/resin"> <ejb-server database="jdbc/test"/> <servlet-mapping url-pattern="/test" servlet-class="demo.HouseServlet"/> </web-app> public interface EntityManager { public <T> T find(Class<T> entityCLass, Object primaryKey); public <T> T getReference(Class<T> entityClass, Object primaryKey); public void flush(); public <T> T merge(T entity); public void persist(Object entity); public void refresh(Object entity); public void remove(Object entity); public FlushModeType getFlushMode(); public void setFlushMode(FlushModeType flushMode); public Query createQuery(String ql); public Query createNamedQuery(String name); public Query createNativeQuery(String sql); public Query createNativeQuery(String sql, Class resultClass); public Query createNativeQuery(String sql, String resultSEtMapping); public void clear(); public void close(); public boolean contains(Object entity); public Object getDelegate(); public boolean isOpen(); public EntityTransaction getTransaction(); public void joinTransaction(); public void lock(Object entity, LockModeType lockMode); } public interface EntityManagerFactory { public EntityManager createEntityManager(); public EntityManager createEntityManager(Map map); public void close(); public boolean isOpen(); } public interface EntityTransaction { public void begin(); public void commit(); public void rollback(); public boolean getRollbackOnly(); public void setRollbackOnly(); public boolean isActive(); } public interface Query { public List getResultList(); public Object getSingleResult(); public int executeUpdate(); public Query setFirstResult(int startPosition); public Query setFlushMode(FlushModeType flushMode); public Query setHint(String hintName, Object value); public Query setMaxResults(int maxResult); public Query setParameter(String name, Object value); public Query setParameter(String name, Date date, TemporalType type); public Query setParameter(String name, Calendar date, TemporalType type); public Query setParameter(int pos, Object value); public Query setParameter(int pos, Date date, TemporalType type); public Query setParameter(int pos, Calendar date, TemporalType type); }

Configures the discriminator column, which select the entity class in an inheritance relationship. Each entity class will have a column value which uniquely selects the class to be loaded.

<deftable>
Property Description Default
name The name of the column
discriminatorType The column type: STRING, CHAR or INTEGER STRING
columnDefinition SQL definition used when creating the column
length default VARCHAR length when creating a STRING column 31
</deftable> @Target(TYPE) @Retention(RUNTIME) public @interface DiscriminatorColumn { String name() default ""; DiscriminatorType discriminatorType() default STRING; String columnDefinition() default ""; int length() default 31; }

Annotates the class as an embeddable value. The class fields will represent a collection of table columns embedded as part of a containing class for the table.

@Target(TYPE) @Retention(RUNTIME) public @interface Embeddable { }

Annotates the class as an entity bean.

See the basic property tutorial and the basic field tutorial for an introduction.

<deftable>
Property Description Default
name The name of the bean The class name (unqualified)
</deftable> @Target(TYPE) @Retention(RUNTIME) public @interface Entity { String name() default ""; }

The fields or properties will be annotated by @Id, @Basic, etc. Amber will detect either field or property annotation by the type for the @Id. In other words, if Amber sees an @Id on a field, it will use field access. If Amber sees @Id on a method, it will use property access.

The `@IdClass` annotation specifies the class to be used to contain a compount primary key.

@Target({TYPE}) @Retention(RUNTIME) public @interface IdClass { Class value(); }

@Inheritance marks the entity bean as supporting inheritance, i.e. the database maps to different Java classes depending on a discriminator value.

<deftable>
Property Description Default
strategy The mapping strategy for inheritance: SINGLE_TABLE, JOINED or TABLE_PER_CLASS SINGLE_TABLE
</deftable> @Target(TYPE) @Retention(RUNTIME) public @interface Inheritance { InteritanceType strategy() default SINGLE_TABLE; }

The `@MappedSuperclass` annotation marks the class as a parent class to an `@Entity`.

@Target({TYPE}) @Retention(RUNTIME) public @interface MappedSuperclass { }

Specifies a secondary database table for an entity bean. The secondary table will contain the fields with a secondaryTable in the @Column.

<deftable>
Property Description Default
name The name of the tableThe unqualified class name.
catalog the table's catalog none
schema the table's schemanone
pkJoinColumns join column to the primary table joins the primary key
uniqueConstraint unique constraints during generation none
</deftable> @Target(TYPE) @Retention(RUNTIME) public @interface SecondaryTable { String name() default ""; String catalog() default ""; String schema() default ""; PrimaryKeyJoinColumn []pkJoinColumns() default {}; UniqueConstraint []uniqueConstraints() default {}; }

Specifies a sequence table to be used for generating keys.

<deftable>
Property Description Default
name The amber name of the sequence table required
sequenceName The SQL name of the sequence table name
initialValue The initial value to seed the generator 0
allocationSize The number of values to increment by for each allocation 50
</deftable> @Target({TYPE, METHOD, FIELD}) @Retention(RUNTIME) public @interface SequenceGenerator { String name(); String sequenceName() default ""; int initialValue() default 0; int allocationSize() default 50; }

Specifies the database table for an entity bean. The default table name is the class name.

<deftable>
Property Description Default
name The name of the table The unqualified class name.
catalog the table's catalog none
schema the table's schema none
uniqueConstraint unique constraints during generation none
</deftable> <def> package javax.persistence; @Target(TYPE) @Retention(RUNTIME) public @interface Table { String name() default ""; String catalog() default ""; String schema() default ""; UniqueConstraint []uniqueConstraints() default {}; }

Specifies a secondary table to be used for generating keys.

<deftable>
Property Description Default
name The amber name of the generator table required
table The SQL name of the generator table name
catalog The SQL catalog of the generator table
schema The SQL schema of the generator table
pkColumnName The SQL column name for the primary key name
valueColumnName The SQL column name for the value
pkColumnName The SQL column name for the primary key's value
initialValue The initial value to seed the generator 0
allocationSize The number of values to increment by for each allocation 50
uniqueConstraints Extra uniqueness constraints when creating the table
</deftable> @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 initialValue() default 0; int allocationSize() default 50; UniqueConstraint []uniqueConstraints() default {}; }

Marks a field as a persistent field.

<deftable>
Property Description Default
fetch EAGER or LAZY fetchingFetchType.EAGER
optional if true, the column may be null true
</deftable> @Target({METHOD, FIELD}) @Retention(RUNTIME) public @interface Basic { FetchType fetch() default EAGER; boolean optional() default true; }

The fetch types are:

- EAGER - fetch the field when the bean is loaded
- LAZY - fetch the field only when the field is used

@Entity public class Course { @Basic public String getName() ... } @Entity public class Course { @Basic(fetch=FetchType.LAZY) public String getMassiveText() ... }

Specifies the field's SQL column name as well as any CREATE TABLE properties for auto generation.

<deftable>
Property Description Default
name The SQL name of the column the field name
unique True for UNIQUE columns false
nullable False for IS NOT NULL columns true
insertable True if column is inserted on as SQL `INSERT` call true
updatable True if column is updated when the field is modified false
columnDefinition SQL to create the column in a CREATE TABLE none
table specified if column is stored in a secondary table none
length the default length for a VARCHAR for a CREATE TABLE 255
precision the default length for a number definition for a CREATE TABLE 0
scale the default length for a number definition for a CREATE TABLE 0
</deftable> @Target({METHOD, FIELD}) @Retention(RUNTIME) public @interface Column { String name() default ""; boolean unique() default false; boolean nullable() default true; boolean insertable() default true; boolean updateable() default true; String columnDefinition() default ""; String table() default ""; int length() default 255; int precision() default 0; int scale() default 0; } @Entity public class Course { @Basic @Column(name="MY_NAME", unique=true, nullable=false, length=32) public String getName() ... }

Marks a field as containing an embeddable value. The field's value will be a class marked as @Embeddable. Applications can use @Embedded fields to gather columns into meaningful groups.

@Target({METHOD, FIELD}) @Retention(RUNTIME) public @interface Embedded { }

Marks a field as a primary key with a embedded class. The field's value class must be marked with `@Embeddable`. Applications can use `@EmbeddedId` to implement compound keys.

@Target({METHOD, FIELD}) @Retention(RUNTIME) public @interface EmbeddedId { }

Marks a field as containing an enumerated value.

<deftable>
Property Description Default
value Specifies whether the enum's ORDINAL or STRING representation should be saved in the database. ORDINAL
</deftable> @Target({METHOD, FIELD}) @Retention(RUNTIME) public @interface Enumerated { EnumType value() default ORDINAL; }

Used with @Id to specify a generator for automatic key generation when new objects are created.

<deftable>
Property Description Default
generator The sequence or table generator name ${'${'}table}_cseq
strategy The auto-generation type: TABLE, SEQUENCE, IDENTITY or AUTO AUTO
</deftable>

The generator types are:

- IDENTITY - the database supplies the new key, e.g. auto_increment, SERIAL, or IDENTITY
- SEQUENCE - use a SEQUENCE type to generate the key
- TABLE - use a @TableGenerator for the key
- AUTO - choose the generator based on the database
  - MySQL - IDENTITY using auto_increment
  - Resin - IDENTITY using auto_increment
  - Postgres - SEQUENCE
  - Oracle - SEQUENCE

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

For SEQUENCE and TABLE, Resin will create the sequence name as "${'${'}table}_cseq".

import javax.persistence.*; @Entity public class Course { @Id @GeneratedValue public long getId() ... } import javax.persistence.*; @Entity public class Course { @Id @GeneratedValue(strategy=GeneratorType.AUTO generator="COURSE_SEQ") public long getId() ... }

Marks a field as a primary key. The `@Id` may be used in combination with `@GeneratedValue` to specify a generator for automatic key generation when new objects are created.

@Target({METHOD, FIELD}) @Retention(RUNTIME) public @interface Id { }

The default column name is "ID".

import javax.persistence.*; @Entity public class Course { @Id @Column(name="t_id") @GeneratedValue public long getId() ... }

Marks a field as containing a large blob value.

@Target({METHOD, FIELD}) @Retention(RUNTIME) public @interface Lob { }

Marks a field as a time-based value.

<deftable>
Property Description Default
value The SQL type used for the field value: DATE, TIME or TIMESTAMP TIMESTAMP
</deftable> @Target({METHOD, FIELD}) @Retention(RUNTIME) public @interface Temporal { TemporalType value() default TIMESTAMP; }

`@Transient` makes a field non-persistent. `@Transient` fields work like the `transient` annotation to prevent properties being saved.

@Target({METHOD,FIELD}) @Retention(RUNTIME) public @interface Transient { }

`@Version` marks a version field, used for optimistic locking.

@Target({METHOD,FIELD}) @Retention(RUNTIME) public @interface Version { }

Defines a join (foreign) columns. Used for @ManyToOne.

See also @Column for corresponding definition for @Basic columns.

See the Many-to-One tutorial for a full example.

<deftable>
Property Description Default
name The column name of the source tablethe column name of the target key
referencedColumnName The target column for composite keysthe single primary key
unique True if unique false
nullable False if IS NOT NULL true
insertable True if the column is inserted on a `create` true
updateable True if the column is updated on field changes true
columnDefinition SQL column definition false
table specifies a secondary table if not in the primary none
</deftable> @Target({TYPE, METHOD, FIELD}) @Retention(RUNTIME) public @interface JoinColumn { String name() default ""; String referencedColumnName() default ""; boolean unique() default false; boolean nullable() default false; boolean insertable() default true; boolean updateable() default true; String columnDefinition() default ""; String table() default ""; } public class Student { @Id @Column(name="student_id") long getId() @ManyToOne @JoinColumn(name="house_id") public House getHouse() } CREATE TABLE Student { student_id BIGINT PRIMARY KEY auto_increment house_id BIGINT REFERENCES House(id) )

Defines a set of join (foreign) columns for composite keys.

@Target({TYPE,METHOD, FIELD}) @Retention(RUNTIME) public @interface JoinColumns { JoinColumn [] value() default{} }

Defines an association table for a many-to-many relation.

<deftable>
Property Description Default
name Table definition for the association table concatening the source and target table names
catalog Database catalog ""
schemaDatabase schema""
joinColumnsColumns from from the association table to the source tableUses the source table primary key
inverseJoinColumnsColumns from from the association table to the target tableUses the target table primary key
</deftable> @Target({METHOD, FIELD}) @Retention(RUNTIME) public @interface JoinTable { String table() default ""; String catalog() default ""; String schema() default ""; JoinColumn []joinColumns() default {}; JoinColumn []inverseJoinColumns() default {}; UniqueContraint []uniqueConstraint() default {}; }

Marks a field as a many-to-many (association) relation.

The column names are the key columns of the source and target tables.

See the many-to-many tutorial for an example.

<deftable>
Property Description Default
cascade Operations which cascade to the target none
fetch EAGER or LAZY fetching FetchType.EAGER
mappedBy Specifies the source relation if a target
targetEntity The class of the target entity the property's type
</deftable> @Target({METHOD, FIELD}) @Retention(RUNTIME) public @interface ManyToMany { String targetEntity default ""; CascadeType []cascade() default {}; FetchType fetch() default LAZY; String mappedBy isInverse() default ""; } @Entity public class Student { @ManyToMany @JoinTable( name="student_course_map", joinColumns={@JoinColumn(name="student_id")}, inverseJoinColumns={@JoinColumn(name="course_id")} ) public Collection getCourses() ... }

Marks a field as a many-to-one (link) relation.

The default column name is the column name of the target key.

See the many-to-one tutorial for an example.

<deftable>
Property Description Default
targetEntity The class of the target entity the property's type
cascade Operations which cascade to the target: ALL, PERSIST, MERGE, REMOVE or REFRESH none
fetch EAGER or LAZY fetching FetchType.EAGER
optional If false, the relation must always have a value true
</deftable> @Target({METHOD, FIELD}) @Retention(RUNTIME) public @interface ManyToOne { String targetEntity default ""; CascadeType []cascade() default {}; FetchType fetch() default EAGER; boolean optional() default true; } @Entity public class Student { @ManyToOne @JoinColumn(name="house") public House getHouse() ... }

Marks a field as key in a Map relationship.

@Target({METHOD, FIELD}) @Retention(RUNTIME) public @interface MapKey { String name() default ""; }

Marks a field as a one-to-many (collection) relation. Because a one-to-many field is dependent, it needs a @ManyToOne relation on the source table which defines the column.

<deftable>
Property Description Default
targetEntity The class of the target entity the property's type
cascade Operations which cascade to the target: ALL, PERSIST, MERGE, REMOVE, and REFRESH none
fetch EAGER or LAZY fetching FetchType.EAGER
mappedBy Specifies the owning @ManyToOne property on the target entity.
</deftable> @Target({METHOD, FIELD}) @Retention(RUNTIME) public @interface OneToMany { String targetEntity default ""; CascadeType []cascade() default {}; FetchType fetch() default EAGER; String mappedBy() default ""; } @Entity public class House { ... @OneToMany(targetEntity=Student.class, mappedBy="house") public Collection getStudents() } @Entity public class Student { ... @ManyToOne @JoinColumn(name="house") public House getHouse() } CREATE TABLE House { id BIGINT PRIMARY KEY ) CREATE TABLE Student { id BIGINT PRIMARY KEY, house BIGINT REFERENCES House(id) )

Marks a field as a one-to-one (dependent link) relation. Because a one-to-one field is dependent, it needs a @ManyToOne relation on the source table which defines the column.

<deftable>
Property Description Default
targetEntity The class of the target entitythe property's type
cascade Operations which cascade to the target: ALL, PERSIST, MERGE, REMOVE, and REFRESH none
fetch EAGER or LAZY fetching FetchType.EAGER
mappedBy Specifies the owning relation
</deftable> @Target({METHOD, FIELD}) @Retention(RUNTIME) public @interface OneToOne { String targetEntity default ""; CascadeType []cascade() default {}; FetchType fetch() default EAGER; boolean optional() default true; String mappedBy() default ""; }

`@OrderBy` specifies the SQL column to use for ordering collection relations.

<deftable>
Property Description Default
name The property name to sort the collection by. the property's type
</deftable> @Target({METHOD, FIELD}) @Retention(RUNTIME) public @interface OrderBy { String value() default ""; }

Amber's non-transactional lifecycle has three important states:

- clean: the bean is loaded from the database
- dirty: the bean has unwritten changes
- hollow: the bean is unloaded (lazily-loaded)

In the diagram below, the red methods (`load()`, `getXXX()`, and `flush()`) query and update the database.

The `aConn.load("1")` method loads the bean from the database and transitions to the clean state.

Calling `test.setData("foo")` will change to the dirty state.

Calling `aConn.flush()` writes the changes to the database and changes to the clean state. Amber may also flush the changes and change to the clean state at any time. `flush()` merely guarantees that the changes will be flushed to the database.

The hollow state represents lazily-loaded entities. many-to-one relations and some queries will return the unloaded bean instead of a loaded bean. When the application calls a `getXXX()` method, the bean will load from the database and change to the clean state. When the application calls a `setXXX()` method, the bean will change to the dirty state.

public class MyServlet extends GenericServlet { @In EntityManagerFactory _factory; @In UserTransaction _trans; ... public void doTest(PrintWriter out) throws IOException { EntityManager aConn = _factory.createManager(); // load() loads test and then detaches it qa.Test test = aConn.load(qa.Test.class, "1"); // test has the loaded values out.println(test.getData()); // but parent is not lazily-loaded when detached, i.e. it's null. qa.Test parent = test.getParent(); aConn.close(); } }

In a transaction, Amber loads the bean from the database, even if it was loaded outside of the transaction. (Exceptions exist for cases like read-only beans.) By loading the bean in the transaction, Amber lets the database handle the transactional locking and state consistency.

Just like the non-transactional clean and dirty states, Amber has transactional clean and dirty states called Persistent-clean and Persistent-dirty. As in the non-transactional case, the hollow state represents lazily-loaded beans.

- persistent-clean: the bean is loaded from the database within the transaction
- persistent-dirty: the bean has been changed
- hollow: the bean is unloaded (lazily-loaded or rolled-back)
- persistent-nonXA: the bean was loaded outside of the transaction (and would need reloading if used in the transaction)

The main differences from the non-transactional lifecycle are:

- Transactions need a load from inside the transaction. Loads before the transaction cannot be reused.
- Updates occur during the commit() call and change to the nonXA-clean state
- Rollbacks change to the hollow state.

The lifecycle description uses a single running example, Test, which has two properties: `getData()` which returns a string, and `getParent()` which is a pointer to another Test object.

<?xml version="1.0" encoding="UTF-8"?> <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"> <package>qa</package> <entity name="Test" class="qa.Test" access="PROPERTY"> <table name="TEST"/> <attributes> <id name="id"> <column name="ID"/> </id> <basic name="data"> <column name="DATA"/> </basic> <many-to-one name="parent"> <join-column name="FK_PARENT"/> </many-to-one> </attributes> </table> </entity> </entity-mappings>
</document>