Caucho Technology
documentation
examples
changes

overview
quick start
installation
command-line
configuration
admin
amber
clustering
caching
database
deployment
ejb 3.0
embedding
filters
hessian
hmtp
ioc
jsp
logging
messaging
performance
quercus/php
remoting
scheduled tasks
security
server push
servlets
third-party
troubleshooting
virtual hosting
watchdog
webapp
xml and xslt

amber


Amber is Resin's implementation of the JPA 1.0 persistence specification, focusing on simplicity and quality.

See Also

Quick Start

  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
Example: House SQL
create table HOUSE (
  id integer auto_increment,
  name varchar(255)
)
Example: House entity
package demo;

import javax.persistence.*;

@Entity
public class House {
  @Id
  @Column(name="id")
  @GeneratedValue
  private int _id;

  @Basic
  @Column(name="name")
  private String _name;
}
Example: HouseServlet
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();
    }
  }
}
META-INF/persistence.xml
<persistence xmlns="http://java.sun.com/xml/ns/persistence" version="1.0">

  <persistence-unit name="test">
  </persistence-unit>

</persistence>
WEB-INF/resin-web.xml
<web-app xmlns="http://caucho.com/ns/resin">

  <ejb-server database="jdbc/test"/>

  <servlet-mapping url-pattern="/test"
                    servlet-class="demo.HouseServlet"/>

</web-app>

API

EntityManager

javax.persistence.EntityManager
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);
}

EntityManagerFactory

javax.persistence.EntityManagerFactory
public interface EntityManagerFactory {
  public EntityManager createEntityManager();
  public EntityManager createEntityManager(Map map);

  public void close();
  public boolean isOpen();
}

EntityTransaction

javax.persistence.EntityTransaction
public interface EntityTransaction {
  public void begin();
  public void commit();
  public void rollback();

  public boolean getRollbackOnly();
  public void setRollbackOnly();
  public boolean isActive();
}

Query

javax.persistence.Query
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);
}

Annotations

Class Annotations

@DiscriminatorColumn

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.

PROPERTYDESCRIPTIONDEFAULT
nameThe name of the column
discriminatorTypeThe column type: STRING, CHAR or INTEGERSTRING
columnDefinitionSQL definition used when creating the column
lengthdefault VARCHAR length when creating a STRING column31
javax.persistence.DiscriminatorColumn
@Target(TYPE)
@Retention(RUNTIME)
public @interface DiscriminatorColumn {
  String name() default "";
  DiscriminatorType discriminatorType() default STRING;
  String columnDefinition() default "";
  int length() default 31;
}

@Embeddable

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.

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

@Entity

Annotates the class as an entity bean.

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

PROPERTYDESCRIPTIONDEFAULT
nameThe name of the beanThe class name (unqualified)
javax.persistence.Entity
@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.

@IdClass

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

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

@Inheritance

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

PROPERTYDESCRIPTIONDEFAULT
strategyThe mapping strategy for inheritance: SINGLE_TABLE, JOINED or TABLE_PER_CLASS SINGLE_TABLE
javax.persistence.Inheritance
@Target(TYPE)
@Retention(RUNTIME)
public @interface Inheritance {
  InteritanceType strategy() default SINGLE_TABLE;
}

@MappedSuperclass

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

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

@SecondaryTable

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

PROPERTYDESCRIPTIONDEFAULT
nameThe name of the tableThe unqualified class name.
catalogthe table's catalognone
schemathe table's schemanone
pkJoinColumnsjoin column to the primary tablejoins the primary key
uniqueConstraintunique constraints during generationnone
javax.persistence.SecondaryTable
@Target(TYPE)
@Retention(RUNTIME)
public @interface SecondaryTable {
  String name() default "";
  String catalog() default "";
  String schema() default "";
  PrimaryKeyJoinColumn []pkJoinColumns() default {};
  UniqueConstraint []uniqueConstraints() default {};
}

@SequenceGenerator

Specifies a sequence table to be used for generating keys.

PROPERTYDESCRIPTIONDEFAULT
nameThe amber name of the sequence tablerequired
sequenceNameThe SQL name of the sequence tablename
initialValueThe initial value to seed the generator0
allocationSizeThe number of values to increment by for each allocation50
javax.persistence.SequenceGenerator
@Target({TYPE, METHOD, FIELD})
@Retention(RUNTIME)
public @interface SequenceGenerator {
  String name();
  String sequenceName() default "";
  int initialValue() default 0;
  int allocationSize() default 50;
}

@Table

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

PROPERTYDESCRIPTIONDEFAULT
nameThe name of the tableThe unqualified class name.
catalogthe table's catalognone
schemathe table's schemanone
uniqueConstraintunique constraints during generationnone
package javax.persistence;

@Target(TYPE)
@Retention(RUNTIME)
public @interface Table {
  String name() default "";
  String catalog() default "";
  String schema() default "";
  UniqueConstraint []uniqueConstraints() default {};
}

@TableGenerator

Specifies a secondary table to be used for generating keys.

PROPERTYDESCRIPTIONDEFAULT
nameThe amber name of the generator tablerequired
tableThe SQL name of the generator tablename
catalogThe SQL catalog of the generator table
schemaThe SQL schema of the generator table
pkColumnNameThe SQL column name for the primary key name
valueColumnNameThe SQL column name for the value
pkColumnNameThe SQL column name for the primary key's value
initialValueThe initial value to seed the generator0
allocationSizeThe number of values to increment by for each allocation50
uniqueConstraintsExtra uniqueness constraints when creating the table
javax.persistence.TableGenerator
@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 {};
}

Property Annotations

@Basic

Marks a field as a persistent field.

PROPERTYDESCRIPTIONDEFAULT
fetchEAGER or LAZY fetchingFetchType.EAGER
optionalif true, the column may be nulltrue
javax.persistence.Basic
@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
Example: string property
@Entity
public class Course {
  @Basic
  public String getName()

  ...
}
Example: lazy-loaded property
@Entity
public class Course {
  @Basic(fetch=FetchType.LAZY)
  public String getMassiveText()

  ...
}

@Column

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

PROPERTYDESCRIPTIONDEFAULT
nameThe SQL name of the columnthe field name
uniqueTrue for UNIQUE columnsfalse
nullableFalse for IS NOT NULL columnstrue
insertableTrue if column is inserted on as SQL INSERT calltrue
updatableTrue if column is updated when the field is modifiedfalse
columnDefinitionSQL to create the column in a CREATE TABLEnone
tablespecified if column is stored in a secondary tablenone
lengththe default length for a VARCHAR for a CREATE TABLE255
precisionthe default length for a number definition for a CREATE TABLE0
scalethe default length for a number definition for a CREATE TABLE0
javax.persistence.Column
@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;
}
Example: @Column for a string property
@Entity
public class Course {
  @Basic
  @Column(name="MY_NAME",
          unique=true,
          nullable=false,
          length=32)
  public String getName()

  ...
}

@Embedded

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.

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

@EmbeddedId

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.

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

@Enumerated

Marks a field as containing an enumerated value.

PROPERTYDESCRIPTIONDEFAULT
valueSpecifies whether the enum's ORDINAL or STRING representation should be saved in the database.ORDINAL
javax.persistence.Enumerated
@Target({METHOD, FIELD})
@Retention(RUNTIME)
public @interface Enumerated {
  EnumType value() default ORDINAL;
}

@GeneratedValue

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

PROPERTYDESCRIPTIONDEFAULT
generatorThe sequence or table generator name${'${'}table}_cseq
strategyThe auto-generation type: TABLE, SEQUENCE, IDENTITY or AUTOAUTO

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
javax.persistence.GeneratedValue
@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".

Example: autoincrement generation
import javax.persistence.*;

@Entity
public class Course {
  @Id
  @GeneratedValue
  public long getId()

  ...
}
Example: sequence generation
import javax.persistence.*;

@Entity
public class Course {
  @Id
  @GeneratedValue(strategy=GeneratorType.AUTO
                  generator="COURSE_SEQ")
  public long getId()

  ...
}

@Id

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.

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

The default column name is "ID".

Example: automatic generation
import javax.persistence.*;

@Entity
public class Course {
  @Id
  @Column(name="t_id")
  @GeneratedValue
  public long getId()

  ...
}

@Lob

Marks a field as containing a large blob value.

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

@Temporal

Marks a field as a time-based value.

PROPERTYDESCRIPTIONDEFAULT
valueThe SQL type used for the field value: DATE, TIME or TIMESTAMPTIMESTAMP
javax.persistence.Temporal
@Target({METHOD, FIELD})
@Retention(RUNTIME)
public @interface Temporal {
  TemporalType value() default TIMESTAMP;
}

@Transient

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

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

@Version

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

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

Relation annotations

@JoinColumn

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.

PROPERTYDESCRIPTIONDEFAULT
nameThe column name of the source tablethe column name of the target key
referencedColumnNameThe target column for composite keysthe single primary key
uniqueTrue if uniquefalse
nullableFalse if IS NOT NULLtrue
insertableTrue if the column is inserted on a createtrue
updateableTrue if the column is updated on field changestrue
columnDefinitionSQL column definitionfalse
tablespecifies a secondary table if not in the primarynone
javax.persistence.JoinColumn
@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 "";
}
Example: Student to House link
public class Student {
  @Id
  @Column(name="student_id")
  long getId()

  @ManyToOne
  @JoinColumn(name="house_id")
  public House getHouse()
}
Example: Student SQL
CREATE TABLE Student {
  student_id BIGINT PRIMARY KEY auto_increment

  house_id BIGINT REFERENCES House(id)
)

@JoinColumns

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

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

@JoinTable

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

PROPERTYDESCRIPTIONDEFAULT
nameTable definition for the association tableconcatening the source and target table names
catalogDatabase 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
javax.persistence.JoinTable
@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 {};
}

@ManyToMany

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.

PROPERTYDESCRIPTIONDEFAULT
cascadeOperations which cascade to the targetnone
fetchEAGER or LAZY fetchingFetchType.EAGER
mappedBySpecifies the source relation if a target
targetEntityThe class of the target entitythe property's type
javax.persistence.ManyToMany
@Target({METHOD, FIELD})
@Retention(RUNTIME)
public @interface ManyToMany {
  String targetEntity default "";
  CascadeType []cascade() default {};
  FetchType fetch() default LAZY;
  String mappedBy isInverse() default "";
}
Example: @ManyToMany link
@Entity
public class Student {
  @ManyToMany
  @JoinTable(
    name="student_course_map",
    joinColumns={@JoinColumn(name="student_id")},
    inverseJoinColumns={@JoinColumn(name="course_id")}
  )
  public Collection getCourses()

  ...
}

@ManyToOne

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.

PROPERTYDESCRIPTIONDEFAULT
targetEntityThe class of the target entitythe property's type
cascadeOperations which cascade to the target: ALL, PERSIST, MERGE, REMOVE or REFRESHnone
fetchEAGER or LAZY fetchingFetchType.EAGER
optionalIf false, the relation must always have a valuetrue
javax.persistence.ManyToOne
@Target({METHOD, FIELD})
@Retention(RUNTIME)
public @interface ManyToOne {
  String targetEntity default "";
  CascadeType []cascade() default {};
  FetchType fetch() default EAGER;
  boolean optional() default true;
}
Example: @ManyToOne link
@Entity
public class Student {
  @ManyToOne
  @JoinColumn(name="house")
  public House getHouse()

  ...
}

@MapKey

Marks a field as key in a Map relationship.

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

@OneToMany

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.

PROPERTYDESCRIPTIONDEFAULT
targetEntityThe class of the target entitythe property's type
cascadeOperations which cascade to the target: ALL, PERSIST, MERGE, REMOVE, and REFRESHnone
fetchEAGER or LAZY fetchingFetchType.EAGER
mappedBySpecifies the owning @ManyToOne property on the target entity.
javax.persistence.OneToMany
@Target({METHOD, FIELD})
@Retention(RUNTIME)
public @interface OneToMany {
  String targetEntity default "";
  CascadeType []cascade() default {};
  FetchType fetch() default EAGER;
  String mappedBy() default "";
}
Example: collection
@Entity
public class House {
  ...
  @OneToMany(targetEntity=Student.class,
             mappedBy="house")
  public Collection getStudents()
}

@Entity
public class Student {
  ...
  @ManyToOne
  @JoinColumn(name="house")
  public House getHouse()
}
Example: Collection SQL
CREATE TABLE House {
  id BIGINT PRIMARY KEY
)

CREATE TABLE Student {
  id BIGINT PRIMARY KEY,

  house BIGINT REFERENCES House(id)
)

@OneToOne

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.

PROPERTYDESCRIPTIONDEFAULT
targetEntityThe class of the target entitythe property's type
cascadeOperations which cascade to the target: ALL, PERSIST, MERGE, REMOVE, and REFRESHnone
fetchEAGER or LAZY fetchingFetchType.EAGER
mappedBySpecifies the owning relation
javax.persistence.OneToOne
@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

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

PROPERTYDESCRIPTIONDEFAULT
nameThe property name to sort the collection by.the property's type
javax.persistence.OrderBy
@Target({METHOD, FIELD})
@Retention(RUNTIME)
public @interface OrderBy {
  String value() default "";
}

Amber Lifecycle

Non-Transactional Lifecycle

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.

Example: Amber outside transaction
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();
  }
}

Transactional Lifecycle

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.

Configuration Files

Example configuration

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.

Example: META-INF/orm.xml
<?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>

Copyright © 1998-2008 Caucho Technology, Inc. All rights reserved.
Resin ® is a registered trademark, and Quercustm, Ambertm, and Hessiantm are trademarks of Caucho Technology.