EJB3 and Hibernate3 Annotations






Hibernate Annotations


EJB3 and Hibernate3 mapping metadata with JDK 5.0 Annotations




Version: 3.0 Preview beta1, 07 04 2005






Please note that this documentation is based on a preview release
of the Hibernate Annotations and implements the Early Draft Release 2 of
EJB 3.0/JSR-220 persistence annotations. However, we expect that this work is already
very close to the final concepts in the new specification. Our goal is to provide
a complete set of ORM annotations, including EJB3 standard annotations as well as
Hibernate3 extensions for cases not covered by the specification. See the href="#gen37">Compliance and Limitations section for more
information.



1. Introduction



Hibernate, like all other object/relational mapping tools, requires metadata that
governs the transformation of data from one representation to the other (and vice
versa). In Hibernate 2.x, mapping metadata is most of the time declared in XML text
files. Another option is XDoclet, utilizing Javadoc source code annotations and a
preprocessor at compile time. The same kind of annotation support is now available in
the standard JDK, although more powerful and better supported by tools. IntelliJ IDEA,
and Eclipse for example, supports auto-completion and syntax highlighting of JDK 5.0
annotations.
The new revision of the EJB specification (JSR-220) uses JDK 5.0 annotations as the
primary metadata mechanism. Hibernate3 implements the EntityManager of JSR-220
(the persistence API). The Hibernate Annotations package contains the EJB3 and Hibernate3
extension annotations and their internal binding to the Hibernate core.



2. Requirements




  • Download and unpack hibernate-annotations-3.0beta1 from the Hibernate website

  • Download and unpack hibernate-3.0 from the Hibernate website



  • Make sure you have JDK 5.0 installed.
    You can of course continue using XDoclet and get some of the benefits of
    annotation-based metadata with older JDK versions. Note that this document only
    describes JDK 5.0 annotations and you have to refer to the XDoclet documentation for
    more information.



    3. Setup and configuration



    First, set up your classpath (after you have created a new project in your favorite IDE):



  • Copy all Hibernate3 core and required 3rd party library files (see lib/README.txt in Hibernate).

  • Copy hibernate-annotations.jar and lib/ejb-3.0-edr2.jar from the
    Hibernate Annotations distribution to your classpath as well.

    We also recommend a small wrapper class to startup Hibernate in a static initializer block,
    known as HibernateUtil. You might have seen this class in various forms in other
    areas of the Hibernate documentation. For Annotation support you have to enhance this
    helper class as follows:





    package hello;

    import org.hibernate.*;
    import org.hibernate.cfg.*;
    import test.*;
    import test.animals.Dog;

    public class HibernateUtil {

    private static final SessionFactory sessionFactory;

    static {
    try {

    sessionFactory = new AnnotationConfiguration()

    .addPackage("test")
    .addAnnotatedClass(Flight.class)
    .addAnnotatedClass(Sky.class)
    .addAnnotatedClass(Person.class)
    .addAnnotatedClass(Dog.class)

    .buildSessionFactory();
    } catch (Throwable ex) {
    // Log exception!
    throw new ExceptionInInitializerError(ex);
    }
    }

    public static Session getSession()
    throws HibernateException {
    return sessionFactory.openSession();
    }
    }



    Interesting here is the use of AnnotationConfiguration and the declaration
    of a package and persistent classes.


    Alternatively, you can declare your annotated packages and classes in your usual
    XML configuration file (usually hibernate.cfg.xml). Here is the equivalent of the
    above declaration




    <!DOCTYPE hibernate-configuration PUBLIC
    "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
    "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">

    <hibernate-configuration>
    <session-factory>
    <mapping resource="test/Boat.hbm.xml"/>
    <mapping package="test"/>
    <mapping class="test.Flight"/>
    <mapping class="test.Sky"/>
    <mapping class="test.Person"/>
    <mapping class="test.animals.Dog"/>

    </session-factory>
    </hibernate-configuration>


    This kind of declaration is certainly a preferred way. Note that you can mix the the hbm.xml use
    and the new annotation one.



    There is no other difference in the way you use Hibernate APIs with Annotations, expect for
    this change in the startup routine or in the configuration file. You can use your favorite
    configuration method for other properties (hibernate.properties, hibernate.cfg.xml, programmatic
    APIs, etc). You can even mix annotated persistent classes and classic hbm.cfg.xml
    declarations with the same SessionFactory. You can however not declare a class several
    times (whether annotated or through hbm.xml). For annotated classes, the classes have to be added
    before their subclasses (this limitation will likely be removed soon), e.g.:





    cfg.addAnnotatedClass(Animal.class);
    cfg.addAnnotatedClass(Dog.class); // OK

    cfg.addAnnotatedClass(Dog.class);
    cfg.addAnnotatedClass(Animal.class); // AnnotationException!



    4. Mapping with EJB3 Annotations



    EJB3 entity beans are plain POJOs. Actually they represent the exact same concept as the
    Hibernate entities. Their mappings are defined through the JDK 5.0
    annotation feature (an XML descriptor syntax hasn't been finalized in the specification).
    Annotations come in two categories, the logical mapping annotations (allowing you to
    describe the object model, the class associations, etc.) and the physical mapping
    annotations (decribing the physical schema, tables, columns, indexes, etc). We will
    mix annotations from both categories in the following code examples.


    Annotations are in the javax.persistence.* package. IntelliJ is know to work well on it.



    4.1 Declaring an entity bean



    Every bound persistent POJO class is an entity bean and is declared using the
    @Entity annotation (at the class level):





    @Entity
    public class Flight implements Serializable {
    Long id;

    @Id
    public Long getId() { return id; }

    public setId(Long id) { this.id = id; }
    }



    For a full example, see Flight.java
    of the test suite.



    @Entity declares the class as an entity bean (i.e. a persistent POJO class),
    @Id declares the identifier property of this entity bean. The other mapping
    declarations are implicit. This configuration by exception concept is central to the
    new EJB3 specification and a major improvement. The class Flight is mapped to
    the Flight table, using the column id as its primary key column.



    The @Entity annotation allows you to define whether an entity bean should be
    accessed through its getters/setters methods (default) or wheher the entity manager should
    access the fields of the object directly:




    @Entity(access = AccessType.PROPERTY)
    or
    @Entity(access = AccessType.FIELD)



    The EJB3 spec requires that you declare annotations on the artefact
    that will be used, i.e. the getter method if you use PROPERTY access, the
    field if you use FIELD access.



    4.1.1 Defining the table



    @Table is set at the class level; it allows you to define the table,
    catalog, and schema names for your entity bean mapping. If no @Table is
    defined the default values are used: the unqualified class name of the entity.





    @Entity(access=AccessType.FIELD)
    @Table(name="tbl_sky")
    public class Sky implements Serializable {
    ...



    You can also define unique constraints to the table using the @UniqueConstraint annotation
    in conjunction with @Table (for a unique constraint bound to a sincle column, refer to @column).
    For a full example, see Sky.java
    of the test suite.



    4.1.2 Versioning for optimistic locking



    You can add optimistic locking capability to an entity bean using the
    @Version annotation:





    @Entity()
    public class Flight implements Serializable {
    ...
    @Version
    @Column(name="OPTLOCK")

    public Integer getVersion() { ... }
    }



    The version property will be mapped to the OPTLOCK column,
    and the entity manager will use it to detect conflicting updates (preventing lost
    updates you might otherwise see with the last-commit-wins strategy).



    4.1.3 Entity specific extensions


    To empower the EJB3 capabilities, hibernate provides specific annotations that
    match hibernate features. The org.hibernate.annotations package contains
    all these annotations extensions. Pleaser refer to the
    Hibernate Annotations API
    for a complete list.


    @org.hibernate.annotations.Entity extends @javax.persistence.Entity :


    • mutable: whether this entity is mutable or not

    • dynamicInsert: allow dynamic SQL for inserts

    • dynamicUpdate: allow dynamic SQL for updates

    • selectBeforeUpdate: Specifies that Hibernate should never perform an
      SQL UPDATE unless it is certain that an object is actually modified.

    • polymorphism: whether the entity polymorphism is of
      PolymorphismType.IMPLICIT (default) or PolymorphismType.IMPLICIT

    • persister: allow the overriding of the default persister implementation

    • optimisticLock: optimistic locking strategy (VERSION, NONE, DIRTY or ALL)


    @org.hibernate.annotations.BatchSize allows you to define the batch size when fetching
    instances of this entity ( eg. @BatchSize(size=4) )

    @org.hibernate.annotations.Proxy defines the lazyness attributes of the entity.
    lazy (default to true) define whether the class is lazy or not. proxyClassName
    is the interface to use for the lazy initializing proxies.

    @org.hibernate.annotations.Where defines an optional SQL WHERE clause used when
    instances of this class is retrieved.

    @org.hibernate.annotations.Check defines an optional check constraints defined
    at the class level.

    @org.hibernate.annotations.Cache defines the caching strategy and region of the class.
    This annotation is defined at the root entity (not the subentities).



    @org.hibernate.annotations.Filter or @Filters define filter(s) to an entity.
    A filter is defined by a name() and by a SQL condition()
    (with potential parameters).

    @org.hibernate.annotations.FilterDef or @FilterDefs define filter
    definition(s) used by filter(s) using the same name. A filter definition has a name()
    and an array of parameters(). A @ParamDef has a name and a type. A @FilterDef(s)
    can be defined at the class or package level.




    @Entity
    @BatchSize(size=5)
    @org.hibernate.annotations.Entity(
    selectBeforeUpdate = true,
    dynamicInsert = true, dynamicUpdate = true,
    optimisticLock = OptimisticLockType.ALL,
    polymorphism = PolymorphismType.EXPLICIT)
    @Where(clause="1=1")
    @Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
    @FilterDef(name="minLength", parameters={ @ParamDef( name="minLength", type="integer" ) } )
    @Filters( {
    @Filter(name="betweenLength", condition=":minLength <= length and :maxLength >= length"),
    @Filter(name="minLength", condition=":minLength <= length")
    } )
    public class Forest {



    Please refer to the test suite's
    entity package for more
    working examples.



    4.2 Mapping simple properties



    4.2.1 Declaring basic property mappings



    By default, every property of an entity bean is mapped persistent, unless you
    annotate it as @Transient. Not having an annotation for your property is
    equivalent to an appropriate basic annotation (see 4.2.4 for more details).
    The @Basic annotation allows
    you to declare the fetching strategy for a property:





    @Transient
    String getLengthInMeter() { ... }

    String getName() {... } // persistent property

    @Basic
    int getLength() { ... } // persistent property

    @Basic(fetch = FetchType.LAZY)
    String getDetailedComment() { ... }



    The lengthInMeter property is mapped transient and will be ignored by the
    entity manager. The name and the length properties are mapped persistent
    and eagerly fetched (the default for simple properties). The detailedComment
    property value will be lazily fetched from the database once a lazy property of the entity
    is accessed for the first time. The compiled code of your class has to be instrumented for
    this feature, please refer to the Hibernate reference documentation. Usually you don't need
    lazy simple property fetching (not to be confused with lazy association fetching) and can avoid
    any build-time bytecode instrumentation with Hibernate. Hibernate will silently disable lazy
    property fetching if you don't instrument the compiled class.


    @Serialized indicates that the property should be persisted as a serialized
    bytestream.


    @Lob indicates that the property should be persisted in a Blob or a Clob depending
    the of LobType. java.sql.Clob, Character[], char[] and String
    can be persisted in a Clob. java.sql.Blob, Byte[] and byte[]
    can be persisted in a Blob.



    	@Serialized
    public Country getCountry() {
    ...
    }

    @Lob(type=LobType.CLOB)
    public String getFullText() {
    return fullText;
    }

    @Lob(type = LobType.BLOB)
    public byte[] getFullCode() {
    return fullCode;
    }



    4.2.2 Declaring column attributes



    The columns use for a property mapping can be defined using the @Column annotation.
    Use it to override default values (see the EJB3 specification for more information on the
    defaults). You can use this annotation at the property level for properties that are, not annotated
    at all, annotated with @Basic, @Version, @Serialized
    and @Lob:





    @Entity()
    public class Flight implements Serializable {
    ...
    @Column(updatable = false, name = "flight_name", nullable = false, length=50)
    public String getName() { ... }



    The name property is mapped to the flight_name column, which is
    not nullable, has a length of 50 and is not updatable (making the property immutable).
    For more attributes of @Column please refer to the EJB3 spec.



    4.2.3 Embedded objects (components)



    It is possible to declare an embedded component inside an entity and even override its
    column mapping. Component classes (also known as user-defined value types) have to be
    annotated at the class level with the @Embeddable annotation. It is
    possible to override the column mapping of an embedded object for a particular entity
    using the @Embedded annotation in the associated property:





    @Entity(access = AccessType.FIELD)
    public class Person implements Serializable {

    // Persistent component using defaults
    Address homeAddress;

    @Embedded({
    @AttributeOverride(name="iso2", column = @Column(name="bornIso2") ),
    @AttributeOverride(name="name", column = @Column(name="bornCountryName") )
    })

    Country bornIn;
    ...
    }







    @Embeddable(access = AccessType.FIELD)
    public class Address implements Serializable {
    String city;
    Country nationality;
    }







    @Embeddable
    public class Country implements Serializable {
    private String iso2;
    private String name;

    public String getIso2() { return iso2; }
    public void setIso2(String iso2) { this.iso2 = iso2; }

    @Column(name="countryName")
    public String getName() { return name; }
    public void setName(String name) { this.name = name; }
    ...
    }



    The Person entity bean has two component properties, homeAddress and
    bornIn. Note that the homeAddress property has not been annotated.
    Hibernate will guess that it is a persistent component after looking for the
    @Embeddable in the Address class. We also override the mapping of
    a column name (to bornCountryName) with the @Embedded and
    @AttributeOverride annotations for each mapped attribute of Country.
    As you can see, Country is also nested component of Address, again using
    auto-detection by Hibernate and EJB3 defaults. Overriding columns of dependent objects
    of dependent objects is currently not supported in the EJB3 spec (user feedbacks are welcome).



    4.2.4 Non annotated property


    • If the property is of a single type, it is mapped as @Basic

    • Otherwise, if the type of the property is annotated as @Embeddable

    • Otherwise, if the type of the property is Serializable, it is mapped as
      @Serialized

    • Otherwise, if the type of the property is java.sql.Clob or
      java.sql.Blob, it is mapped as @Lob with the appropriate
      LobType



    4.2.5 Property specific extensions


    @org.hibernate.annotations.Type overrides the default hibernate type used: this
    is generally not necessary since the type is correctly inferred by Hibernate.
    Please refer to the Hibernate reference guide for more informations on the Hibernate types.

    @org.hibernate.annotations.TypeDef and @org.hibernate.annotations.TypeDefs
    allows you to define type defintions. These annotations are placed at the class or package level.
    Note that these definitions will be global for the session factory (even at the class level)
    and that type definition has to be defined before any usage.




    @TypeDefs(
    {
    @TypeDef(
    name="caster",
    typeClass = CasterStringType.class,
    parameters = {
    @Parameter(name="cast", value="lower")
    }
    )
    }
    )
    package org.hibernate.test.annotations.entity;

    ...
    public class Forest {
    @Type(type="caster")
    public String getSmallText() {
    ...
    }



    4.3 Mapping identifier properties



    The @Id annotation lets you define which property is the identifier of your
    entity bean. It also allows you to define the identifier generation strategy:




    • AUTO - either identity column or sequence depending the underlying DB
    • TABLE - table holding the id
    • IDENTITY - identity column
    • SEQUENCE - sequence
    • NONE - the application has the responsability to set the id


    The following example shows a sequence generator using the SEQ_STORE
    configuration (see below):





    @Id(generate=GeneratorType.SEQUENCE, generator="SEQ_STORE")
    public Integer getId() { ... }



    The next example uses the identity generator:





    @Id(generate=GeneratorType.IDENTITY)
    public Integer getId() { ... }



    The AUTO generator is the preferred type for portable applications (accross several dB vendors).
    The identifier generation configuration can be shared for several @Id mappings
    with the generator attribute. There are several configurations available through
    @SequenceGenerator, @TableGenerator and @GeneratorTable. The scope
    of a generator can be the application or the class. Class-defined generators are not visible outside
    the class and can override application level generators. Application level generators are
    defined at package level
    (see package-info.java):






    @javax.persistence.GeneratedIdTable(
    name="GEN_TABLE",
    table = @Table(name="GENERATOR_TABLE"),
    pkColumnName = "key",
    valueColumnName = "hi"
    )
    @javax.persistence.TableGenerator(
    name="EMP_GEN",
    tableName="GEN_TABLE",
    pkColumnValue="EMP",
    allocationSize=20
    )
    @javax.persistence.SequenceGenerator(
    name="SEQ_GEN",
    sequenceName="my_sequence"
    )

    package org.hibernate.test.metadata;



    If cfg.addPackage("org.hibernate.test.metadata") is used to initialize the
    Hibernate config, EMP_GEN and SEQ_GEN are application level generators.
    EMP_GEN defines a table based id generator using the hilo algorithm with a
    max_lo of 20 and keeping the hi value in a row of a table defined by the GEN_TABLE
    @GeneratorTable. The row has EMP as a primary key value. The table (described by
    the @GeneratorTable) is GENERATOR_TABLE, had the column key
    (which hold the primary key) and the column hi (which hold the next hi value used).


    SEQ_GEN defines a sequence generator using a sequence
    named my_sequence. Note that this version of Hibernate Annotations does not
    handle initialValue and allocationSize parameters in the SequenceGenerator.

    The next example shows the definition of a sequence generator in a class scope:





    @Entity
    @javax.persistence.SequenceGenerator(
    name="SEQ_STORE",
    sequenceName="my_sequence"
    )

    public class Store implements Serializable {
    private Long id;

    @Id(generate=GeneratorType.SEQUENCE, generator="SEQ_STORE")
    public Long getId() { return id; }
    }



    This class will use a sequence named my_sequence and the SEQ_STORE
    generator is not visible in other classes. Note that you can Have a look at the Hibernate Annotations
    tests in the org.hibernate.test.metadata.id package for more examples.



    You can define a composite primary key through several syntaxes:

  • annotate the component property as @Id and make the component class @Embeddable

  • annotate the component property as @EmbeddedId

  • annotate the class as @IdClass (this mapping is currently not supported by the
    implementation).

    Have a look at Child.java and
    Parent.java for some
    examples.



    4.3 Mapping inheritance



    EJB3 supports the three types of inheritance:



    • Table per Class Strategy: the <class> element in Hibernate
    • Single Table per Class Hierarchy Strategy: the <subclass> element in Hibernate
    • Joined Subclass Strategy: the <joined-subclass> element in Hibernate


    The chosen strategy is declared at the class level using the @Inheritance annotation.

    4.3.1 Table per class



    This strategy has many drawbacks (esp. with polymorphic queries and associations)
    explained in the EJB3 spec,the Hibernate reference documentation, Hibernate in Action,
    and many other places. It is commonly used for the top level of an inheritance
    hierarchy:





    @Entity()
    @Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
    public class Flight implements Serializable {



    You have to declare inheritance on the leave classes (note: this is an
    interpretation of the spec and is subject to change).



    4.3.2 Single table per class hierarchy



    All properties of all super- and subclasses are mapped to the same table, instances
    are distinquished with a special discriminator column:





    @Entity()
    @Inheritance(
    strategy=InheritanceType.SINGLE_TABLE,
    discriminatorType=DiscriminatorType.STRING,
    discriminatorValue="Plane"
    )
    @DiscriminatorColumn(name="planetype")

    public class Plane { ... }

    @Entity()
    @Inheritance(
    discriminatorValue="A320"
    )

    public class A320 extends Plane { ... }



    Plane is the superclass, it defines the inheritance strategy
    InheritanceType.SINGLE_TABLE, the discriminator type DiscriminatorType.STRING,
    and the discriminator value used for planes, "Plane". It also defines the
    discriminator column through the @DiscriminatorColumn(name="planetype"). Most of
    these atttributes have sensible default values. The default name of the discriminator column
    is TYPE, and (for Hibernate) the default discriminator value is the fully qualified
    class name. A320 is a subclass; you only have to define discriminatorValue
    if you won't accept the default. The strategy and the discriminator type is implicit.



    4.3.2 Joined subclasses



    This strategy has to be declared on all the subclasses. The @InheritanceJoinColumn
    and @InheritanceJoinColumns annotations define the primary key(s) of the joined
    subclass table. Note that the current implementation does not support implicit
    @InheritanceJoinColumns:





    @Entity()
    @Inheritance(strategy=InheritanceType.JOINED )
    public class Boat implements Serializable { ... }

    @Entity()
    @Inheritance(strategy=InheritanceType.JOINED)
    public class Ferry extends Boat { ... }

    @Entity(access=AccessType.FIELD)
    @Inheritance(strategy=InheritanceType.JOINED)
    @InheritanceJoinColumn(name="BOAT_ID")

    public class AmericaCupClass extends Boat { ... }



    Every entity bean declares the JOINED strategy, the Ferry
    table is joined with the Boat table using the same primary key names. The
    AmericaCupClass table is joined with Boat using the join
    condition Boat.id = AmericaCupClass.BOAT_ID.



    4.4 Mapping entity bean associations



    4.4.1 One-to-one



    You can associate entity beans with a one-to-one relationship using @OneToOne.
    There are two cases for one-to-one associations: either the associated entities share the
    same primary keys values or a foreign key is held by one of the entities (note that this FK
    column in the database should be constrained unique to simulate one-to-one multiplicity).



    First, we map a real one-to-one association using shared primary keys:





    @Entity
    public class Body {
    @Id
    public Long getId() { return id; }

    @OneToOne(cascade = CascadeType.ALL, usePKasFK=true)
    public Heart getHeart() {
    return heart;
    }
    ...
    }







    @Entity
    public class Heart {
    @Id(generate = GeneratorType.NONE)
    public Long getId() { ...}
    }



    Unfortunatly, in the current release of Hibernate Annotations, the Heart
    identifier value has to be set manually by the application developer. Support for a
    Hibernate-style "foreign" identifier generator will be added soon.



    In the following example, the associated entities are linked through a foreign key
    column :





    @Entity
    public class Customer implements Serializable {
    @OneToOne(cascade = CascadeType.ALL)
    @JoinColumn(name="passport_fk")
    public Passport getPassport() {
    ...
    }

    @Entity
    public class Passport implements Serializable {
    @OneToOne(mappedBy = "passport")
    public Customer getOwner() {
    ...
    }



    A Customer is linked to a Passport, with a foreign key column named
    passport_fk in the Customer table. The join column is declared with the
    @JoinColumn annotation which looks like the @Column annotation. It has
    one more parameter named referencedColumnName. This parameter declares the column
    in the targetted entity that will be used to the join. The current implementation does not
    support the referencedColumnName attribute, so Hibernate will join to the primary
    key (default value in the specification).


    The association may be bidirectional. In a bidirectional relationship, one of the side
    has to be the owner : the owner is responsible for the association column(s) update. To
    declare a side as non responsible for the relationship, the attribute mappedBy
    is used. mappedBy refers the property name of the association on the owner side.
    In our case, this is 'passport'. As you can see, you don't have to (must not) declare the
    joining column since it is already on the other side.


    If no @JoinColumn is declared on the owner side, the defaults apply. A join
    column(s) will be created in the owner table and its name will be the concatenation of the
    name of the relationship in the owner side, '_' (underscore), and the name of the primary
    key column(s) in the owned side. In this example 'passport_id' because the property name is
    passport and the column id of Passport is 'id'.



    4.4.2 Many-to-one



    Many-to-one associations are declared at the property level with the annotation
    @ManyToOne; it has a parameter named targetEntity which describes the
    target entity name. You usually don't need this parameter since the default value (the
    type of the property that stores the association) is good in almost all cases:





    @Entity()
    public class Flight implements Serializable {
    @ManyToOne( cascade = {CascadeType.CREATE, CascadeType.MERGE} )
    @JoinColumn(name="COMP_ID")
    public Company getCompany() {
    return company;
    }
    ...
    }



    The @JoinColumn attribute is optional, the default value(s) is like in one to one,
    the concatenation of the
    name of the relationship in the owner side, '_' (underscore), and the name of the primary
    key column in the owned side. In this example 'company_id' because the property name is
    company and the column id of Company is 'id'.


    In case of a bidirectional, a many to one is always the owner side.



    4.4.3 One-to-many



    One-to-many associations are declared at the property level with the annotation
    @OneToMany. In the current EJB3 specification, you can map Collection
    and Set (Map and List are not defined in the spec so far).
    Unless the collection is a generic, you'll have to defined targetEntity. One to many
    associations may be bidirectional.



    4.4.3.1 Bidirectional

    Since many to one are always the owner side of a bidirectional relationship in the EJB3 spec,
    the one to many association is annotated by @OneToMany( mappedBy=... )


    @Entity
    public class Troop {
    @OneToMany(mappedBy="troop")
    public Set<Soldier> getSoldiers() {
    ...
    }

    @Entity
    public class Soldier {
    @ManyToOne
    @JoinColumn(name="troop_fk")
    public Troop getTroop() {
    ...


    Troop has a bidirectional one to many relationship with Soldier
    through the 'troop' property. You don't have to (must not) define any physical
    mapping in the mappedBy side.



    4.4.3.2 Unidirectional

    A unidirectional one to many using a foreign key column in the owned entity is not
    so common and not really recommanded. We strongly advise you to use a join table
    for this kind of association (as explained in the next section). This kind of
    association is described through a @JoinColumn



    @Entity
    public class Customer implements Serializable {
    @OneToMany(cascade=CascadeType.ALL, fetch=FetchType.EAGER)
    @JoinColumn(name="CUST_ID")
    public Set<Ticket> getTickets() {
    ...
    }

    @Entity
    public class Ticket implements Serializable {
    ... //no bidir
    }


    Customer describes a unidirectional relationship with Ticket using the
    join column 'CUST_ID'.



    4.4.3.3 Unidirectional with join table

    A unidirectional one to many with join table is much preferred. This association
    is described through a @AssociationTable.


    @Entity()
    public class Trainer {
    @OneToMany
    @AssociationTable(
    table=@Table(name="TrainedMonkeys"),
    joinColumns = { @JoinColumn( name="trainer_id") },
    inverseJoinColumns = @JoinColumn( name="monkey_id")
    )
    public Set<Monkey> getTrainedMonkeys() {
    ...
    }

    @Entity
    public class Monkey {
    ... //no bidir
    }


    Trainer describes a unidirectional relationship with Monkey using the
    join table 'TrainedMonkeys', with a foreign key 'trainer_id' to Trainer (joinColumns)
    and a foreign key 'monkey_id' to Monkey (inversejoinColumns).



    4.4.3.4 Default values


    Without describing any physical mapping, a unidirectional one to many
    with join table is used. The table name is the concatenation of the owner
    table name, '_', and the other side table name. The foreign key name(s) referencing
    the owner table is the concatenation of the owner table, '_', and the owner
    primary key column(s) name. The foreign key name(s) referencing the other side is the
    concatenation of the owner property name, '_', and the other side primary key
    column(s) name. A unique constraint is added to the foreign key referencing the
    other side table to reflect the one to many.




    @Entity()
    public class Trainer {
    @OneToMany
    public Set<Tiger> getTrainedTigers() {
    ...
    }

    @Entity
    public class Tiger {
    ... //no bidir
    }


    Trainer describes a unidirectional relationship with Tiger using the
    join table 'Trainer_Tiger', with a foreign key 'trainer_id' to Trainer
    (table name, '_', trainer id) and a foreign key 'trainedTigers_id' to Monkey
    (property name, '_', Tiger primary column).



    4.4.4 Many-to-many



    4.4.4.1 description


    A many-to-many association is defined logically using the @ManyToMany annotation.
    You also have to describe the association table and the join conditions using the
    @AssociationTable annotation. If the association is bidirectional, one side has to be
    the owner and one side has to be the inverse end (ie. it will be ignored when updating the
    relationship values in the association table):





    @Entity()
    public class Employer implements Serializable {
    @ManyToMany(
    targetEntity="org.hibernate.test.metadata.manytomany.Employee",
    cascade={CascadeType.CREATE, CascadeType.MERGE}
    )
    @AssociationTable(
    table=@Table(name="EMPLOYER_EMPLOYEE"),
    joinColumns={@JoinColumn(name="EMPER_ID")},
    inverseJoinColumns={@JoinColumn(name="EMPEE_ID")}
    )

    public Collection getEmployees() {
    return employees;
    }
    ...
    }







    @Entity()
    public class Employee implements Serializable {
    @ManyToMany(
    cascade={CascadeType.CREATE, CascadeType.MERGE},
    mappedBy="employees"
    )
    public Collection getEmployers() {
    return employers;
    }
    }



    We've already shown the many declarations and the detailed attributes for associations.
    We'll go deeeper in the @AssociationTable description, it defines a @Table,
    an array of join columns (an array in annotation is defined using { A, B, C }),
    and an array of inverse join columns. The latter ones are the columns of the association
    table which refer to the Employee primary key (the "other side"). Note that the current implementation
    mandates that you join the entity primary keys, referencedColumnName for
    other non pk columns is not supported.


    As seen previously, the other side don't have to (must not) describe the physical
    mapping: a simple mappedBy argument containing the owner side property name bind
    the two.



    4.4.4.1 Default values


    As any other annotations, most values are guessed in a many to many relationship.
    Without describing any physical mapping in a unidirectional many to many
    the following rules applied. The table name is the concatenation of the owner
    table name, '_' and the other side table name. The foreign key name(s) referencing the owner
    table is the concatenation of the owner table name, '_' and the owner primary key
    column(s). The foreign key name(s) referencing the other side is the concatenation of
    the owner property name, '_', and the other side primary key column(s). These are
    the same rules used for a unidirectional one to many relationship.





    @Entity()
    public class Store {
    @ManyToMany(cascade = CascadeType.PERSIST)
    public Set<City> getImplantedIn() {
    ...
    }

    @Entity()
    public class City {
    ... //no bidirectional relationship
    }


    A 'Store_Table' is used as the join table. The 'Store_id' column is a foreign key
    to the 'Store' table. The 'implantedIn_id' column is a foreign key to the 'City' table.


    Without describing any physical mapping in a bidirectional many to many
    the following rules applied. The table name is the concatenation of the owner
    table name, '_' and the other side table name. The foreign key name(s) referencing the owner
    table is the concatenation of the other side property name, '_', and the owner primary
    key column(s). The foreign key name(s) referencing the other side is the concatenation of
    the owner property name, '_', and the other side primary key column(s). These are
    the same rules used for a unidirectional one to many relationship





    @Entity()
    public class Store {
    @ManyToMany(cascade = {CascadeType.PERSIST, CascadeType.MERGE})
    public Set<Customer> getCustomers() {
    ...
    }

    @Entity()
    public class Customer {
    @ManyToMany(mappedBy="customers")
    public Set<Store> getStores() {
    ...
    }


    A 'Store_Customer' is used as the join table. The 'stores_id' column is a foreign key
    to the 'Store' table. The 'customers_id' column is a foreign key to the 'City' table.


    Check the unit tests contained in the manytomany package,

    4.4.5 Transitive persistence with cascading



    You probably have noticed the cascade taking an array of CascadeType as a value.
    The cascade concept in EJB3 is very is similar to the transitive persistence and cascading
    of operations in Hibernate, but with slighty different semantics and cascading types:




    • CascadeType.PERSIST: cascades the persist (create) operation to associated entities persist() is called or if the entity is managed
    • CascadeType.MERGE: cascades the merge operation to associated entities if merge() is called or if the entity is managed
    • CascadeType.REMOVE: cascades the remove operation to associated entities if delete() is called
    • CascadeType.REFRESH: cascades the refresh operation to associated entities if refresh() is called
    • CascadeType.ALL: all of the above


    Please refer to the chapter 6.3 of the EJB3 specification for more information on
    cascading and and create/merge semantics.



    4.4.6 Association fetching



    You have the ability to either eagerly or lazily fetch associated entities. The fetch
    parameter can be set to FetchType.LAZY or FetchType.EAGER. EAGER will
    try to use an outer join select to retrieve the associated object, while LAZY is the
    default and will only trigger a select when the associated object is accessed for the first time.



    4.4.7 Collection specific extensions


    It is possible to set

    • the batch size for collections using @BatchSize

    • the where clause, using @Where

    • the check clause, using @Check

    • the caching strategy through the @Cache annotation.


    Please refer to the previous descriptions of these annotations
    for more informations



    4.5 Mapping composite primary and foreign keys



    Composite primary keys use a component class as the primary key representation, so you'd use
    the @Id and @Embeddable annotations. Alternatively, you can use the
    @EmbeddedId annotation. Note that the dependent class has to be
    serializable. This implementation only support composite identifiers with component classes.





    @Entity
    public class RegionalArticle implements Serializable {

    @Id(generate = GeneratorType.NONE)
    public RegionalArticlePk getPk() { ... }
    }

    @Embeddable(access = AccessType.FIELD)
    public class RegionalArticlePk implements Serializable { ... }


    or alternatively




    @Entity
    public class RegionalArticle implements Serializable {

    @EmbeddedId()
    public RegionalArticlePk getPk() { ... }
    }

    public class RegionalArticlePk implements Serializable { ... }



    @Embeddable can define either a field or a property access strategy for the
    component. Composite foreign keys (if not using the default sensitive values) are defined
    on associations using the @JoinColumns element, which is basically an array
    of @JoinColumns. It is considered a good practice
    to express referencedColumnNames explicitely. Otherwise, Hibernate will suppose
    that you use the same order of columns as in the primary key declaration.





    @Entity(access = AccessType.FIELD)
    public class Parent implements Serializable {
    @Id
    public ParentPk id;
    public int age;

    @OneToMany(cascade=CascadeType.ALL)
    @JoinColumns ({
    @JoinColumn(name="parentCivility", referencedColumnName = "isMale"),
    @JoinColumn(name="parentLastName", referencedColumnName = "lastName"),
    @JoinColumn(name="parentFirstName", referencedColumnName = "firstName")
    })

    public Set<Child> children; //unidirectional
    ...
    }







    @Entity(access = AccessType.FIELD)
    public class Child implements Serializable {
    @Id(generate = GeneratorType.AUTO)
    public Integer id;

    @ManyToOne()
    @JoinColumns ({
    @JoinColumn(name="parentCivility", referencedColumnName = "isMale"),
    @JoinColumn(name="parentLastName", referencedColumnName = "lastName"),
    @JoinColumn(name="parentFirstName", referencedColumnName = "firstName")
    })

    public Parent parent; //unidirectional
    }







    @Embeddable(access = AccessType.FIELD)
    public class ParentPk implements Serializable {
    String firstName;
    String lastName;
    ...
    }





    Note the explicit usage of the referencedColumnName.



    A many-to-many association works the same way, you can find an example in
    Man.java,
    ManPk.java,
    Woman.java,
    WomanPk.java

    4.6 Mapping secondary tables



    You can map a single entity bean to several tables using the @SecondaryTable
    or @SecondaryTables class level annotations. To express that a column is in
    a particular table, use the secondaryTable parameter of @Column or
    @JoinColumn. You can find some examples in
    Cat.java,
    Life.java,
    Death.java

    5. Mapping Queries


    You can map EJBQL/HQL queries using annotations. @NamedQuery and
    @NamedQueries can be defined at the class or at the package level.
    However their definition is global to the session factory scope.
    A named query is defined by its name and the actual query string.



    @javax.persistence.NamedQueries(
    @javax.persistence.NamedQuery(name="plane.getAll", queryString="select p from Plane p")
    )
    package org.hibernate.test.annotations.query;

    ...

    @Entity
    @NamedQuery(name="night.moreRecentThan", queryString="select n from Night n where n.date >= :date")
    public class Night {
    ...
    }

    public class MyDao {
    doStuff() {
    Query q = s.getNamedQuery("night.moreRecentThan");
    q.setDate( "date", aMonthAgo );
    List results = q.list();
    ...
    }
    ...
    }



    5. Compliance and limitations




    3.0 Preview beta1 (07-04-2005) based on the EJB3 Early Draft 2
    --------------------------------------------------------------
    * support parameters in @Type (HBX-197)
    * support @TypeDef at package and class level
    * HBX-166 support @Lob for Character[],char[], String, byte[] and Byte[] (experimental)
    * HBX-159/HBX-140 add @Filter(s) and @FilterDef(s) (Matthew Inger, Magnus Sandberg)
    * HBX-44 @OneToOne support composite PK
    * @OneToOne is supported except for true bidirectional @OneToOne
    * Add @Cache annotation: allow to define caching on root entities and on collections (,eg @Cache(usage=CacheConcurrencyStrategy.TRANSACTIONAL, region="specificCacheRegion") )
    * Support @OneToMany default (ie using an association table)
    * HBX-164 insertable/updatable of @JoinColumn now work in @ManyToOne processing (Mario Ivankovits, Emmanuel Bernard)
    * HBX-153 @Id(generate=GeneratorType.AUTO, generator="my_potential_sequence") now work (Pablo Nussembaum)
    * Support @ManyToMany wo @AssociationTable (ie defaults)
    * Support @ManyToMany(mappedBy)
    * Support @OneToMany(mappedBy) (no JoinColumn needed on the @OneToMany side)
    * Appropriate default value when no @JoinColumn is defined in a ManyToOne
    * rename @GeneratorTable to @GeneratedIdTable
    * rename CREATE to PERSIST, add REFRESH cascade style
    * support Mapping Defaults for Non-Relationship Fields or Properties algorithm as defined in the EJB3 spec
    * support @Serialized
    * support @Lob for java.sql.Clob and java.sql.Blob
    * allow embedded object declaration wo @Embeddable (if @Embedded or @EmbeddedId is present in the property)
    * support for @EmbeddedId
    * rename DependentAttribute to AttributeOverride, Dependent to Embedded and DependentObject to Embeddable
    * support @ManyToOne in embedded objects
    * support for @NamedQuery and @NamedQueries (EJBQL)
    * move javax.ejb.* into javax.persistence.* and update copyright header

    3.0alpha3 (28-02-2005)
    ----------------------
    * HBX-116 Support for Where clause in classes and collections @Where(clause="")
    * HBX-115 Support for class proxying configuration: @Proxy(lazy=false, proxyClassName="my.Interface")
    * HBX-88 Support for hibernate type abstraction through @Type (only on basic properties for now)
    * HBX-108 Support @BatchSize(size=n) for entities and collections
    * HBX-107 implements @org.hibernate.annotations.Entity
    * HBX-103 handle abstract classes
    * HBX-83 precision & scale support for column (Bogdan Ghidireac)

    3.0alpha2 (25-01-2005)
    ----------------------
    * HBX-61 Support for @UniqueConstraint (except primaryKey=true)
    * HBX-60 Support for a proper @TableGenerator (using MultipleHiLoPerTableGenerator)
    * HBX-63 Support @GeneratorTable
    * HBX-68 Add declarative configuration of annotated classes
    * HBX-74 Rollback the HB-1315 fix: dialect no longer have to be set in hibernate.properties


    Hibernate-annotations-3.0alpha1 based on the EJB3 Early Draft 1 (6.01.2005)
    ---------------------------------------------------------------------------
    * Support for EJB3 annotations:
    - @Transient
    - @Column (not primaryKey)
    - @JoinColumn (referencedColumnName - only for a reference to a PK, not primaryKey)
    - @Version
    - @Basic
    - @Entity
    - @Table (not uniqueConstraints)
    - @AccessType
    - @Id
    - @CascadeType
    - @FetchType
    - @GeneratorType (NONE, IDENTITY, TABLE, SEQUENCE)
    - @TableGenerator (with scope visibility)
    - @SequenceGenerator (with scope visibility, does not support initialValue() and allocationSize())
    - *not* @GeneratorTable (will have to write a new TableHiloGenerator, but it can wait)
    - @ManyToOne (not optional)
    - @OneToMany (Set and Collection, generics version or not, JoinColumn not guessed)
    - @OneToOne
    but not optional
    no composite PK/FK
    - @ManyToMany
    - @AssociationTable (Has to be on both sides)
    - @Inheritance
    - @InheritanceType (has to be defined on every classes of the hierarchy for JOINED strategy,
    not very clear about the TABLE_PER_CLASS strategy)
    - @DiscriminatorColumn
    - @DiscriminatorType
    - @InheritanceJoinColumn
    - @InheritanceJoinColumns
    this annotation for Composite PK Entities has to be explicit, I do not respect the implicit semantic of the EJB3 spec
    - @SecondaryTable (@OneToMany @JoinColumn(secondaryTable="..." does not work yet due to H3 core issue HHH-36
    - @SecondaryTables
    this annotation for Composite PK Entities has to be explicit, I do not respect the implicit semantic of the EJB3 spec
    - @DependentObject
    - @Dependent
    - @DependentAttribute (only for basic properties as per the spec)
    - @Id in conjunction with @DependentObject (composite primary keys)
    - @JoinColumns in conjunction with @ManytoOne, @OneToMany, @ManytoMany
    - note that the composite FK columns have to be in the same table (no != secondary tables). This is probably a weird case and certainly a not recommanded one.


    Still missing or incomplete features compared to the EJB3 spec
    --------------------------------------------------------------
    - use of referencedColumnName for column other than the PK ones (HX-62)
    - better semantic of cascade (HBX-47)
    - Support for a true bidirectional one to one relationship (HBX-177)
    - inheritance declaration parsing should be more robust (HBX-186)
    - annotations inheritance and superclasses (HBX-157) (to be addressed by the next draft)
    - appropriate fetching mode on queries (HBX-87)
    - implicit join column declaration in inheritance with composite PK (HBX-75)
    - @UniqueConstraint(primaryKey=true) (HBX-82)
    - support for initialValue and allocationSize in @SequenceGenerator (HBX-59)
    - finish support of optional=false (HBX-190)
    - @IdClass (HBX-213)


    6. Useful links



    Hibernate Annotations API

    The EJB3 Specification

    The EJB3 JBoss tutorial

    The Hibernate reference guide

    Hibernate In Action



  • Posted by 아름프로
    BLOG main image

    카테고리

    분류 전체보기 (539)
    이야기방 (19)
    토론/정보/사설 (16)
    IBM Rational (9)
    U-IT (0)
    SOA/WS/ebXML (110)
    개발방법론/모델링 (122)
    J2SE (34)
    J2EE (60)
    DataBase (39)
    Open Projects (30)
    BP/표준화 (50)
    Apache Projects (15)
    Web/보안/OS (22)
    Tools (7)
    AJAX/WEB2.0 (1)
    Linux/Unix (1)
    영어 (0)
    비공개방 (0)

    최근에 올라온 글

    최근에 달린 댓글

    최근에 받은 트랙백

    달력

    «   2024/05   »
    1 2 3 4
    5 6 7 8 9 10 11
    12 13 14 15 16 17 18
    19 20 21 22 23 24 25
    26 27 28 29 30 31

    글 보관함

    Total :
    Today : Yesterday :