Hibernate.orgCommunity Documentation

Chapitre 5. Mappage O/R de base

5.1. Déclaration de mappage
5.1.1. Doctype
5.1.2. Hibernate-mappage
5.1.3. Classe
5.1.4. id
5.1.5. La méthode getter de l'identifiant
5.1.6. Optimisation du générateur d'identifiants
5.1.7. composite-id
5.1.8. Discriminator
5.1.9. Version (optionnel)
5.1.10. Timestamp (optionnel)
5.1.11. Property
5.1.12. Plusieurs-à-un
5.1.13. Un-à-un
5.1.14. Natural-id
5.1.15. Component, dynamic-component
5.1.16. Propriétés
5.1.17. Subclass
5.1.18. Joined-subclass
5.1.19. Union-subclass
5.1.20. Join
5.1.21. Key
5.1.22. Éléments column et formula
5.1.23. Import
5.1.24. Any
5.2. Types Hibernate
5.2.1. Entités et valeurs
5.2.2. Types valeurs de base
5.2.3. Types de valeur personnalisés
5.3. Mapper une classe plus d'une fois
5.4. SQL quoted identifiers
5.5. Métadonnées alternatives
5.5.1. Utilisation de XDoclet
5.5.2. Utilisation des annotations JDK 5.0
5.6. Propriétés générées
5.7. Column read and write expressions
5.8. Objets auxiliaires de la base de données

Les mappages objet/relationnel sont généralement définis dans un document XML. Le document de mappage est conçu pour être lisible et éditable à la main. Le langage de mappage est Java-centrique, c'est-à-dire que les mappages sont construits à partir de déclarations de classes persistantes et non à partir de déclarations de tables.

Remarquez que même si beaucoup d'utilisateurs de Hibernate préfèrent écrire les fichiers de mappages XML à la main, plusieurs outils existent pour générer ce document, notamment XDoclet, Middlegen et AndroMDA.

Commençons avec un exemple de mappage :


<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
      "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
          "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">

<hibernate-mapping package="eg">

        <class name="Cat"
            table="cats"
            discriminator-value="C">

                <id name="id">
                        <generator class="native"/>
                </id>

                <discriminator column="subclass"
                     type="character"/>

                <property name="weight"/>

                <property name="birthdate"
                    type="date"
                    not-null="true"
                    update="false"/>

                <property name="color"
                    type="eg.types.ColorUserType"
                    not-null="true"
                    update="false"/>

                <property name="sex"
                    not-null="true"
                    update="false"/>

                <property name="litterId"
                    column="litterId"
                    update="false"/>

                <many-to-one name="mother"
                    column="mother_id"
                    update="false"/>

                <set name="kittens"
                    inverse="true"
                    order-by="litter_id">
                        <key column="mother_id"/>
                        <one-to-many class="Cat"/>
                </set>

                <subclass name="DomesticCat"
                    discriminator-value="D">

                        <property name="name"
                            type="string"/>

                </subclass>

        </class>

        <class name="Dog">
                <!-- mapping for Dog could go here -->
        </class>

</hibernate-mapping
>

Étudions le contenu du document de mappage. Nous ne décrirons que les éléments et attributs du document utilisés par Hibernate à l'exécution. Le document de mappage contient aussi des attributs et éléments optionnels qui agissent sur le schéma de base de données exporté par l'outil de génération de schéma. (Par exemple l'attribut not-null).

Tous les mappages XML devraient utiliser le doctype indiqué. En effet vous trouverez le fichier DTD à l'URL ci-dessus, dans le répertoire hibernate-x.x.x/src/org/hibernate ou dans hibernate3.jar. Hibernate va toujours chercher la DTD dans son classpath en premier lieu. Si vous constatez des recherches de la DTD sur Internet, vérifiez votre déclaration de DTD par rapport au contenu de votre classpath.

Comme mentionné précédemment, Hibernate tentera en premier lieu de résoudre les DTD dans leur classpath. Il réussit à le faire en enregistrant une implémentation personnalisée de org.xml.sax.EntityResolver avec le SAXReader qu'il utilise pour lire les fichiers xml. Cet EntityResolver personnalisé reconnaît deux espaces de nommage systemId différents :

Un exemple d'utilisation de l'espace de nommage utilisateur:


<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC '-//Hibernate/Hibernate Mapping DTD 3.0//EN' 'http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd' [
<!ENTITY version "3.5.6-Final">
<!ENTITY today "September 15, 2010">

    <!ENTITY types SYSTEM "classpath://your/domain/types.xml">


]>


<hibernate-mapping package="your.domain">
    <class name="MyEntity">
        <id name="id" type="my-custom-id-type">
            ...
        </id>
    <class>
    &types;
</hibernate-mapping>

Where types.xml is a resource in the your.domain package and contains a custom typedef.

Cet élément a plusieurs attributs optionnels. Les attributs schema et catalog indiquent que les tables mentionnées dans ce mappage appartiennent au schéma nommé et/ou au catalogue. S'ils sont spécifiés, les noms de tables seront qualifiés par les noms de schéma et de catalogue. L'attribut default-cascade indique quel type de cascade sera utilisé par défaut pour les propriétés et collections qui ne précisent pas l'attribut cascade. L'attribut auto-import nous permet d'utiliser par défaut des noms de classes non qualifiés dans le langage de requête, par défaut.

<hibernate-mapping
         schem(1)a="schemaName"
         catal(2)og="catalogName"
         defau(3)lt-cascade="cascade_style"
         defau(4)lt-access="field|property|ClassName"
         defau(5)lt-lazy="true|false"
         auto-(6)import="true|false"
         packa(7)ge="package.name"
 />

1

schema (optionnel) : le nom d'un schéma de base de données.

2

catalog (optionnel) : le nom d'un catalogue de base de données.

3

default-cascade (optionnel - par défaut vaut : none) : un type de cascade par défaut.

4

default-access (optionnel - par défaut vaut : property) : Comment hibernate accèdera aux propriétés. On peut aussi redéfinir sa propre implémentation de PropertyAccessor.

5

default-lazy (optionnel - par défaut vaut : true) : Valeur par défaut pour des attributs lazy non spécifiés des mappages de classe et de collection.

6

auto-import (optionnel - par défaut vaut : true) : spécifie si l'on peut utiliser des noms de classes non qualifiés (de classes de ce mappage) dans le langage de requête.

7

package (optionnel) : préfixe de paquetage par défaut pour les noms de classe non qualifiés du document de mappage.

Si deux classes persistantes possèdent le même nom de classe (non qualifié), vous devez configurer auto-import="false". Hibernate lancera une exception si vous essayez d'assigner le même nom "importé" à deux classes.

Notez que l'élément hibernate-mappage vous permet d'imbriquer plusieurs mappages de <class> persistantes, comme dans l'exemple ci-dessus. Cependant il est recommandé (et c'est parfois une exigence de certains outils) de mapper une seule classe persistante (ou une seule hiérarchie de classes) par fichier de mappage et de nommer ce fichier d'après le nom de la superclasse persistante, par exemple Cat.hbm.xml, Dog.hbm.xml, ou en cas d'héritage, Animal.hbm.xml.

Déclarez une classe persistante avec l'élément class. Part exemple :

<class
        name="(1)ClassName"
        table=(2)"tableName"
        discri(3)minator-value="discriminator_value"
        mutabl(4)e="true|false"
        schema(5)="owner"
        catalo(6)g="catalog"
        proxy=(7)"ProxyInterface"
        dynami(8)c-update="true|false"
        dynami(9)c-insert="true|false"
        select(10)-before-update="true|false"
        polymo(11)rphism="implicit|explicit"
        where=(12)"arbitrary sql where condition"
        persis(13)ter="PersisterClass"
        batch-(14)size="N"
        optimi(15)stic-lock="none|version|dirty|all"
        lazy="(16)true|false"
        entity(17)-name="EntityName"
        check=(18)"arbitrary sql check condition"
        rowid=(19)"rowid"
        subsel(20)ect="SQL expression"
        abstra(21)ct="true|false"
        node="element-name"
/>

1

name (optionnel) : le nom Java complet de la classe (ou interface) persistante. Si cet attribut est absent, nous supposons que ce mappage ne se rapporte pas à une entité POJO.

2

table (optionnel - par défaut le nom non-qualifié de la classe) : le nom de sa table en base de données.

3

discriminator-value (optionnel - par défaut le nom de la classe) : une valeur permettant de distinguer les différentes sous-classes utilisées dans le comportement polymorphique. Les valeurs null et not null sont autorisées.

4

mutable (optionnel, vaut true par défaut) : spécifie que des instances de la classe sont (ou non) immuables.

5

schema (optionnel) : surcharge le nom de schéma spécifié par l'élément racine <hibernate-mappage>.

6

catalog (optionnel) : surcharge le nom du catalogue spécifié par l'élément racine <hibernate-mappage>.

7

proxy (optionnel) : spécifie une interface à utiliser pour l'initialisation différée (lazy loading) des proxies. Vous pouvez indiquer le nom de la classe elle-même.

8

dynamic-update (optionnel, par défaut à false) : spécifie que les SQL UPDATE doivent être générés à l'exécution et contenir uniquement les colonnes dont les valeurs ont été modifiées.

9

dynamic-insert (optionnel, par défaut à false) : spécifie que les SQL INSERT doivent être générés à l'exécution et ne contenir que les colonnes dont les valeurs sont non nulles.

10

select-before-update (optionnel, par défaut à false): spécifie que Hibernate ne doit jamais exécuter un SQL UPDATE sans être certain qu'un objet a été réellement modifié. Dans certains cas, (en réalité, seulement quand un objet transient a été associé à une nouvelle session par update()), cela signifie que Hibernate exécutera un SQL SELECT pour déterminer si un SQL UPDATE est véritablement nécessaire.

11

polymorphism (optionnel, vaut implicit par défaut) : détermine si, pour cette classe, une requête polymorphique implicite ou explicite est utilisée.

12

where (optionnel) spécifie une clause SQL WHERE à utiliser lorsque l'on récupère des objets de cette classe.

13

persister (optionnel) : spécifie un ClassPersister particulier.

14

batch-size (optionnel, par défaut = 1) : spécifie une "taille de lot" pour remplir les instances de cette classe par identifiant en une seule requête.

15

optimistic-lock (optionnel, par défaut = version) : détermine la stratégie de verrouillage optimiste.

(16)

lazy (optionnel) : l'extraction différée (lazy fetching) peut être totalement désactivée en configurant lazy="false".

(17)

entity-name (optional - defaults to the class name): Hibernate3 allows a class to be mapped multiple times, potentially to different tables. It also allows entity mappings that are represented by Maps or XML at the Java level. In these cases, you should provide an explicit arbitrary name for the entity. See Section 4.4, « Modèles dynamiques » and Chapitre 19, Mappage XML for more information.

(18)

check (optionnel) : expression SQL utilisée pour générer une contrainte de vérification check multi-lignes pour la génération automatique de schéma.

(19)

rowid (optionnel) : Hibernate peut utiliser des ROWID sur les bases de données qui utilisent ce mécanisme. Par exemple avec Oracle, Hibernate peut utiliser la colonne additionnelle rowid pour des mise à jour rapides si cette option vaut rowid. Un ROWID est un détail d'implémentation et représente la localisation physique d'un uplet enregistré.

(20)

subselect (optionnel) : permet de mapper une entité immuable en lecture-seule sur un sous-select de base de données. Utile pour avoir une vue au lieu d'une table de base, mais à éviter. Voir plus bas pour plus d'informations.

(21)

abstract (optionnel) : utilisé pour marquer des superclasses abstraites dans des hiérarchies de <union-subclass>.

Il est tout à fait possible d'utiliser une interface comme nom de classe persistante. Vous devez alors déclarer les classes implémentant cette interface en utilisant l'élément <subclass>. Vous pouvez faire persister toute classe interne static. Vous devez alors spécifier le nom de la classe par la notation habituelle des classes internes, c'est à dire eg.Foo$Bar.

Les classes immuables, mutable="false", ne peuvent pas être modifiées ou supprimées par l'application. Cela permet à Hibernate de faire quelques optimisations mineures sur les performances.

L'attribut optionnel proxy permet les initialisations différées des instances persistantes de la classe. Hibernate retournera initialement des proxies CGLIB qui implémentent l'interface nommée. Le véritable objet persistant ne sera chargé que lorsqu'une méthode du proxy sera appelée. Voir plus bas le paragraphe abordant les Proxies et leur initialisation différée (lazy initialization).

Le polymorphisme implicite signifie que des instances de la classe seront retournées par une requête qui utilise les noms de la classe ou de chacune de ses superclasses ou encore des interfaces implémentées par cette classe ou ses superclasses. Les instances des classes filles seront retournées par une requête qui utilise le nom de la classe elle même. Le polymorphisme explicite signifie que les instances de la classe ne seront retournées que par une requête qui utilise explicitement son nom et que seules les instances des classes filles déclarées dans les éléments <subclass> ou <joined-subclass> seront retournées. Dans la majorités des cas la valeur par défaut, polymorphism="implicit", est appropriée. Le polymorphisme explicite est utile lorsque deux classes différentes sont mappées à la même table (ceci permet d'écrire une classe "légère" qui ne contient qu'une partie des colonnes de la table - voir la partie design pattern du site communautaire).

L'attribut persister vous permet de personnaliser la stratégie de persistance utilisée pour la classe. Vous pouvez, par exemple, spécifier votre propre sous-classe de org.hibernate.persister.EntityPersister ou vous pourriez aussi fournir une nouvelle implémentation de l'interface org.hibernate.persister.ClassPersister qui proposerait une persistance via, par exemple, des appels de procédures stockées, de la sérialisation vers des fichiers plats ou un annuaire LDAP. Voir org.hibernate.test.CustomPersister pour un exemple simple (d'une "persistance" vers une Hashtable).

Notez que les paramètres dynamic-update et dynamic-insert ne sont pas hérités par les sous-classes et peuvent donc être spécifiés pour les éléments <subclass> ou <joined-subclass>. Ces paramètres peuvent améliorer les performances dans certains cas, mais peuvent aussi les amoindrir. À utiliser en connaissance de causes.

L'utilisation de select-before-update va généralement faire baisser les performances. Ce paramètre est pratique pour éviter l'appel inutile par un déclenchement de mise à jour de base de donnée, quand on ré-attache un graphe d'instances à une Session.

Si vous utilisez le dynamic-update, les différentes stratégies de verrouillage optimiste sont les suivantes :

Nous encourageons très fortement l'utilisation de colonnes de version/timestamp pour le verrouillage optimiste avec Hibernate. C'est la meilleure stratégie en ce qui concerne les performances et la seule qui gère correctement les modifications sur les instances détachées (c'est à dire lorsqu'on utilise Session.merge()).

Il n'y a pas de différence entre table et vue pour le mappage Hibernate, comme on peut s'y attendre, cela est transparent au niveau base de données (remarquez que certaines BDD ne supportent pas les vues correctement, notamment pour les mise à jour). Il est possible que vous souhaitiez utiliser une vue mais vous ne puissiez pas en créer une sur votre BDD (c'est-à-dire avec un schéma ancien). Dans ces cas, vous pouvez mapper une entité immuable en lecture seule sur une expression sous-select SQL donnée :


<class name="Summary">
    <subselect>
        select item.name, max(bid.amount), count(*)
        from item
        join bid on bid.item_id = item.id
        group by item.name
    </subselect>
    <synchronize table="item"/>
    <synchronize table="bid"/>
    <id name="name"/>
    ...
</class
>

Déclarez les tables à synchroniser avec cette entité pour assurer que le flush automatique se produise correctement, et pour que les requêtes sur l'entité dérivée ne renvoient pas des données périmées. Le <subselect> est disponible comme attribut ou comme élément de mappage imbriqué.

Les classes mappées doivent déclarer la clé primaire de la table en base de données. La plupart des classes auront aussi une propriété de type JavaBeans présentant l'identifiant unique d'une instance. L'élément <id> sert à définir le mappage entre cette propriété et la colonne de la clé primaire.

<id
        name="(1)propertyName"
        type="(2)typename"
        column(3)="column_name"
        unsave(4)d-value="null|any|none|undefined|id_value"
        access(5)="field|property|ClassName">
        node="element-name|@attribute-name|element/@attribute|."

        <generator class="generatorClass"/>
</id
>

1

name (optionnel) : nom de la propriété de l'identifiant.

2

type (optionnel) : nom indiquant le type Hibernate.

3

column (optionnel - le nom de la propriété est pris par défaut) : nom de la colonne de la clé primaire.

4

unsaved-value (optionnel - devient par défaut une valeur "sensible") : une valeur de propriété d'identifiant qui indique que l'instance est nouvellement instanciée (non sauvegardée), et qui la distingue des instances détachées qui ont été sauvegardées ou chargées dans une session précédente.

5

access (optionnel - par défaut property) : la stratégie que doit utiliser Hibernate pour accéder aux valeurs des propriétés.

Si l'attribut name est absent, Hibernate considère que la classe ne possède pas de propriété d'identifiant.

L'attribut unsaved-value n'est presque jamais nécessaire dans Hibernate3.

La déclaration alternative <composite-id> permet l'accès aux données d'anciens systèmes qui utilisent des clés composées. Son utilisation est fortement déconseillée pour d'autres cas.

L'élément enfant <generator> nomme une classe Java utilisée pour générer les identifiants uniques pour les instances des classes persistantes. Si des paramètres sont requis pour configurer ou initialiser l'instance du générateur, ils sont passés en utilisant l'élément <param>.


<id name="id" type="long" column="cat_id">
        <generator class="org.hibernate.id.TableHiLoGenerator">
                <param name="table"
>uid_table</param>
                <param name="column"
>next_hi_value_column</param>
        </generator>
</id
>

Tous les générateurs implémentent l'interface org.hibernate.id.IdentifierGenerator. C'est une interface très simple ; certaines applications peuvent proposer leurs propres implémentations spécialisées. Cependant, Hibernate propose une série d'implémentations intégrées. Il existe des noms raccourcis pour les générateurs intégrés :

increment

génère des identifiants de type long, short ou int qui ne sont uniques que si aucun autre processus n'insère de données dans la même table. Ne pas utiliser en environnement clusterisé.

identity

prend en charge les colonnes d'identité dans DB2, MySQL, MS SQL Server, Sybase et HypersonicSQL. L'identifiant renvoyé est de type long, short ou int.

sequence

utilise une séquence dans DB2, PostgreSQL, Oracle, SAP DB, McKoi ou un générateur dans Interbase. L'identifiant renvoyé est de type long, short ou int

hilo

utilise un algorithme hi/lo pour générer de façon efficace des identifiants de type long, short ou int, en prenant comme source de valeurs "hi" une table et une colonne (par défaut hibernate_unique_key et next_hi respectivement). L'algorithme hi/lo génère des identifiants uniques pour une base de données particulière seulement.

seqhilo

utilise un algorithme hi/lo pour générer efficacement des identifiants de type long, short ou int, en prenant une séquence en base nommée.

uuid

utilise un algorithme de type UUID 128 bits pour générer des identifiants de type string, unique au sein d'un réseau (l'adresse IP est utilisée). Le UUID est encodé en une chaîne de nombre héxadécimaux de longueur 32.

guid

utilise une chaîne GUID générée par la base pour MS SQL Server et MySQL.

native

choisit identity, sequence ou hilo selon les possibilités offertes par la base de données sous-jacente.

assigned

permet à l'application d'affecter un identifiant à l'objet avant que la méthode save() soit appelée. Il s'agit de la stratégie par défaut si aucun <generator> n'est spécifié.

select

récupère une clé primaire assignée par un déclencheur (trigger) de base de données en sélectionnant la ligne par une clé unique quelconque et en extrayant la valeur de la clé primaire.

foreign

utilise l'identifiant d'un autre objet associé. Habituellement utilisé en conjonction avec une association <one-to-one> sur la clé primaire.

sequence-identity

Une stratégie de génération de séquence spécialisée qui utilise une séquence de base de données pour la génération réelle de valeurs, tout en utilisant JDBC3 getGeneratedKeys pour retourner effectivement la valeur d'identifiant générée, comme faisant partie de l'exécution de la déclaration insert. Cette stratégie est uniquement prise en charge par les pilotes Oracle 10g pour JDK 1.4. Notez que les commentaires sur ces déclarations insert sont désactivés à cause d'un bogue dans les pilotes d'Oracle.

A partir de la version 3.2.3, 2 générateurs représentent une nouvelle conception de 2 aspects séparés de la génération d'identifiants. Le premier aspect est la portabilité de la base de données; le second est l'optimization, c'est à dire que vous n'avez pas à interroger la base de données pour chaque requête de valeur d'identifiant. Ces deux nouveaux générateurs sont sensés prendre la place de générateurs décrits ci-dessus, ayant pour préfixe 3.3.x. Cependant, ils sont inclus dans les versions actuelles, et peuvent être référencés par FQN.

Le premier de ces nouveaux générateurs est org.Hibernate.ID.Enhanced.SequenceStyleGenerator qui est destiné, tout d'abord, comme un remplacement pour le générateur séquence et, deuxièmement, comme un générateur de portabilité supérieur à natif. C'est parce que natif a généralement le choix entre identité et séquence qui ont des sémantiques largement différentes, ce qui peut entraîner des problèmes subtils en observant la portabilité des applications. org.Hibernate.ID.Enhanced SequenceStyleGenerator., cependant, réalise la portabilité d'une manière différente. Il choisit entre une table ou une séquence dans la base de données pour stocker ses valeurs s'incrémentant, selon les capacités du dialecte utilisé. La différence avec natif c'est que de stockage basé sur les tables ou basé sur la séquence ont la même sémantique. En fait, les séquences sont exactement ce qu'Hibernate essaie d'émuler avec ses générateurs basée sur les tables. Ce générateur a un certain nombre de paramètres de configuration :

Le deuxième de ces nouveaux générateurs est org.Hibernate.ID.Enhanced.TableGenerator, qui est destiné, tout d'abord, comme un remplacement pour le générateur de la table, même si elle fonctionne effectivement beaucoup plus comme org.Hibernate.ID.MultipleHiLoPerTableGeneratoret deuxièmement, comme une remise en œuvre de org.Hibernate.ID.MultipleHiLoPerTableGenerator, qui utilise la notion d'optimizers enfichables. Essentiellement ce générateur définit une table susceptible de contenir un certain nombre de valeurs d'incrément différents simultanément à l'aide de plusieurs lignes distinctement masquées. Ce générateur a un certain nombre de paramètres de configuration :

  • table_name (en optin - valeur par défaut = hibernate_sequences): le nom de la table à utiliser.

  • value_column_name (en option - valeur par défaut =next_val): le nom de la colonne contenue dans la table utilisée pour la valeur.

  • segment_column_name (en option - par défaut = sequence_name): le nom de la colonne de la table qui est utilisée pour contenir la "segment key". Il s'agit de la valeur qui identifie la valeur d'incrément à utiliser.

  • segment_value (en option - par défaut = par défaut): La "segment key"valeur pour le segment à partir de laquelle nous voulons extraire des valeurs d'incrémentation pour ce générateur.

  • segment_value_length (en option - par défaut = 255): Utilisée pour la génération de schéma ; la taille de la colonne pour créer cette colonne de clé de segment.

  • initial_value (en option - par défaut est 1 : La valeur initiale à récupérer à partir de la table.

  • increment_size (en option - par défaut = 1): La valeur par laquelle les appels à la table, qui suivent, devront différer.

  • optimizer (optional - defaults to ): See Section 5.1.6, « Optimisation du générateur d'identifiants »

For identifier generators that store values in the database, it is inefficient for them to hit the database on each and every call to generate a new identifier value. Instead, you can group a bunch of them in memory and only hit the database when you have exhausted your in-memory value group. This is the role of the pluggable optimizers. Currently only the two enhanced generators (Section 5.1.5, « La méthode getter de l'identifiant  » support this operation.

  • aucun (en général il s'agit de la valeur par défaut si aucun optimizer n'a été spécifié): n'effectuera pas d'optimisations et n'interrogera pas la base de données à chaque demande.

  • hilo: applique un algorithme hi/lo autour des valeurs extraites des base de données. Les valeurs de la base de données de cet optimizer sont censées être séquentielles. Les valeurs extraites de la structure des base de données pour cet optimizer indique le "numéro de groupe". Le increment_size est multiplié par cette valeur en mémoire pour définir un groupe de "hi value".

  • mise en commun: tout comme dans le cas de hilo, cet optimizer tente de réduire le nombre d'interrogations vers la base de données. Ici, cependant, nous avons simplement stocké la valeur de départ pour le "prochain groupe"dans la structure de la base de données plutôt qu'une valeur séquentielle en combinaison avec un algorithme de regroupement en mémoire. Ici, increment_size fait référence aux valeurs provenant de la base de données.


<composite-id
        name="propertyName"
        class="ClassName"
        mapped="true|false"
        access="field|property|ClassName">
        node="element-name|."

        <key-property name="propertyName" type="typename" column="column_name"/>
        <key-many-to-one name="propertyName" class="ClassName" column="column_name"/>
        ......
</composite-id
>

Pour une table avec clé composée, vous pouvez mapper plusieurs attributs de la classe comme propriétés identifiantes. L'élément <composite-id> accepte les mappages de propriétés <key-property> et les mappages <key-many-to-one> comme éléments enfants.


<composite-id>
        <key-property name="medicareNumber"/>
        <key-property name="dependent"/>
</composite-id
>

Vos classes persistantes doivent surcharger les méthodes equals() et hashCode() pour implémenter l'égalité d'identifiant composite. Elles doivent aussi implémenter l'interface Serializable.

Malheureusement, cette approche signifie qu'un objet persistant est son propre identifiant. Il n'y a pas d'autre moyen pratique de "manipuler" l'objet que par l'objet lui-même. Vous devez instancier une instance de la classe persistante elle-même et peupler ses attributs identifiants avant de pouvoir appeler la méthode load() pour charger son état persistant associé à une clé composée. Nous appelons cette approche "identifiant composé embarqué" et ne la recommandons pas pour des applications complexes.

Une seconde approche, appelée identifiant composé mappé, consiste à dupliquer les propriétés identifiantes nommées dans l'élément <composite-id>) à la fois dans la classe persistante et dans une classe identifiante particulière.


<composite-id class="MedicareId" mapped="true">
        <key-property name="medicareNumber"/>
        <key-property name="dependent"/>
</composite-id
>

Dans cet exemple, la classe d'identifiant composée,MedicareId et la classe mappée elle-même, possèdent les propriétés medicareNumber et dependent. La classe identifiante doit redéfinir equals() et hashCode() et implémenter Serializable. Le désavantage de cette approche est la duplication du code.

Les attributs suivants servent à configurer un identifiant composé mappé :

We will describe a third, even more convenient approach, where the composite identifier is implemented as a component class in Section 8.4, « Les composants en tant qu'identifiants composites ». The attributes described below apply only to this alternative approach:

  • name (optionnel, requis pour cette approche) : une propriété de type composant qui contient l'identifiant composé (voir chapitre 9).

  • access (optionnel - par défaut property) : la stratégie que doit utiliser Hibernate pour accéder aux valeurs des propriétés.

  • class (optionnel - par défaut le type de la propriété déterminé par réflexion) : la classe composant utilisée comme identifiant (voir prochaine section).

La troisième approche, un composant d'identifiant, est celle que nous recommandons pour toutes vos applications.

L'élément <discriminator> est nécessaire pour la persistance polymorphique qui utilise la stratégie de mappage de table par hiérarchie de classe et déclare une colonne discriminante de la table. La colonne discriminante contient des valeurs marqueur qui permettent à la couche de persistance de savoir quelle sous-classe instancier pour une ligne particulière de table en base. Un nombre restreint de types peuvent être utilisés : string, character, integer, byte, short, boolean, yes_no, true_false.

<discriminator
        column(1)="discriminator_column"
        type="(2)discriminator_type"
        force=(3)"true|false"
        insert(4)="true|false"
        formul(5)a="arbitrary sql expression"
/>

1

column (optionnel - par défaut à class), le nom de la colonne discriminante.

2

type (optionnel - par défaut à string) un nom indiquant le type Hibernate.

3

force (optionnel - par défaut à false) "oblige" Hibernate à spécifier une valeur discriminante autorisée même quand on récupère toutes les instances de la classe de base.

4

insert (optionnel - par défaut à true) à passer à false si la colonne discriminante fait aussi partie d'un identifiant composé mappé (Indique à Hibernate de ne pas inclure la colonne dans les SQL INSERT s).

5

formula (optionnel) une expression SQL arbitraire qui est exécutée quand un type doit être évalué. Permet la discrimination basée sur le contenu.

Les véritables valeurs de la colonne discriminante sont spécifiées par l'attribut discriminator-value des éléments <class> et <subclass>.

L'attribut force n'est utile que si la table contient des lignes avec des valeurs "extra" discriminantes qui ne sont pas mappées à une classe persistante. Ce ne sera généralement pas le cas.

En utilisant l'attribut formula vous pouvez déclarer une expression SQL arbitraire qui sera utilisée pour évaluer le type d'une ligne :


<discriminator
    formula="case when CLASS_TYPE in ('a', 'b', 'c') then 0 else 1 end"
    type="integer"/>

L'élément <version> est optionnel et indique que la table contient des données versionnées. C'est particulièrement utile si vous avez l'intention d'utiliser des transactions longues (voir plus-bas).

<version
        column(1)="version_column"
        name="(2)propertyName"
        type="(3)typename"
        access(4)="field|property|ClassName"
        unsave(5)d-value="null|negative|undefined"
        genera(6)ted="never|always"
        insert(7)="true|false"
        node="element-name|@attribute-name|element/@attribute|."
/>

1

column (optionnel - par défaut égal au nom de la propriété) : le nom de la colonne contenant le numéro de version.

2

name : le nom d'un attribut de la classe persistante.

3

type (optionnel - par défaut à integer) : le type du numéro de version.

4

access (optionnel - par défaut property) : la stratégie que doit utiliser Hibernate pour accéder aux valeurs des propriétés.

5

unsaved-value (optionnel - par défaut à undefined) : une valeur de la propriété d'identifiant qui indique que l'instance est nouvellement instanciée (non sauvegardée), et qui la distingue des instances détachées qui ont été sauvegardées ou chargées dans une session précédente. Undefined indique que la valeur de la propritété identifiant devrait être utilisée.

6

generated (optional - defaults to never): specifies that this version property value is generated by the database. See the discussion of generated properties for more information.

7

insert (optionnel - par défaut à true) : indique si la colonne de version doit être incluse dans les ordres SQL insert. Peut être configuré à false si et seulement si la colonne de la base de données est définie avec une valeur par défaut égale à 0.

Les numéros de version doivent avoir les types Hibernate long, integer, short, timestamp ou calendar.

Une propriété de version ou un timestamp ne doit jamais être null pour une instance détachée, ainsi Hibernate pourra détecter toute instance ayant une version ou un timestamp null comme transient, quelles que soient les stratégies unsaved-value spécifiées. Déclarer un numéro de version ou un timestamp "nullable" est un moyen pratique d'éviter tout problème avec les ré-attachements transitifs dans Hibernate, particulièrement utile pour ceux qui utilisent des identifiants assignés ou des clés composées .

L'élément optionnel <timestamp> indique que la table contient des données horodatées (timestamped). Cela sert d'alternative à l'utilisation de numéros de version. Les timestamps (ou horodatage) sont par nature une implémentation moins fiable pour le verrouillage optimiste. Cependant, l'application peut parfois utiliser l'horodatage à d'autres fins.

<timestamp
        column(1)="timestamp_column"
        name="(2)propertyName"
        access(3)="field|property|ClassName"
        unsave(4)d-value="null|undefined"
        source(5)="vm|db"
        genera(6)ted="never|always"
        node="element-name|@attribute-name|element/@attribute|."
/>

1

column (optionnel - par défaut devient le nom de la propriété) : le nom d'une colonne contenant le timestamp.

2

name : le nom d'une propriété au sens JavaBean de type Java Date ou Timestamp de la classe persistante.

3

access (optionnel - par défaut property) : la stratégie que doit utiliser Hibernate pour accéder aux valeurs des propriétés.

4

unsaved-value (optionnel - par défaut à null) : propriété dont la valeur est un numéro de version qui indique que l'instance est nouvellement instanciée (non sauvegardée), et qui la distingue des instances détachées qui ont été sauvegardées ou chargées dans une session précédente. (undefined indique que la valeur de propriété identifiant devrait être utilisée).

5

source (optionnel - par défaut à vm) : d'où Hibernate doit-il récupérer la valeur du timestamp? Depuis la base de données ou depuis la JVM d'exécution? Les valeurs de timestamp de la base de données provoquent une surcharge puisque Hibernate doit interroger la base pour déterminer la prochaine valeur mais cela est plus sûr lorsque vous fonctionnez dans un cluster. Remarquez aussi que certains des Dialect s ne supportent pas cette fonction, et que d'autres l'implémentent mal, à cause d'un manque de précision (Oracle 8 par exemple).

6

generated (optional - defaults to never): specifies that this timestamp property value is actually generated by the database. See the discussion of generated properties for more information.

L'élément <property> déclare une propriété persistante de la classe au sens JavaBean.

<property
        name="(1)propertyName"
        column(2)="column_name"
        type="(3)typename"
        update(4)="true|false"
        insert(4)="true|false"
        formul(5)a="arbitrary SQL expression"
        access(6)="field|property|ClassName"
        lazy="(7)true|false"
        unique(8)="true|false"
        not-nu(9)ll="true|false"
        optimi(10)stic-lock="true|false"
        genera(11)ted="never|insert|always"
        node="element-name|@attribute-name|element/@attribute|."
        index="index_name"
        unique_key="unique_key_id"
        length="L"
        precision="P"
        scale="S"
/>

1

name : nom de la propriété, avec une lettre initiale en minuscule.

2

column (optionnel - par défaut au nom de la propriété) : le nom de la colonne mappée. Cela peut aussi être indiqué dans le(s) sous-élément(s) <column> imbriqués.

3

type (optionnel) : nom indiquant le type Hibernate.

4

update, insert (optionnel - par défaut à true) : indique que les colonnes mappées devraient être incluses dans des déclarations SQL UPDATE et/ou des INSERT. Mettre les deux à false autorise une propriété pure dérivée dont la valeur est initialisée de quelque autre propriété qui mappe à la même colonne(s) ou par un trigger ou une autre application. (utile si vous savez qu'un trigger affectera la valeur à la colonne).

5

formula (optionnel) : une expression SQL qui définit la valeur pour une propriété calculée. Les propriétés calculées ne possèdent pas leur propre mappage.

6

access (optionnel - par défaut property) : la stratégie que doit utiliser Hibernate pour accéder aux valeurs des propriétés.

7

lazy (optionnel - par défaut à false) : indique que cette propriété devrait être chargée en différé (lazy loading) quand on accède à la variable d'instance pour la première fois (nécessite une instrumentation du bytecode lors de la phase de construction).

8

unique (optionnel) : génère le DDL d'une contrainte d'unicité pour les colonnes. Permet aussi d'en faire la cible d'une property-ref.

9

not-null (optionnel) : génère le DDL d'une contrainte de nullité pour les colonnes.

10

optimistic-lock (optionnel - par défaut à true) : indique si les mise à jour de cette propriété nécessitent ou non l'acquisition d'un verrou optimiste. En d'autres termes, cela détermine s'il est nécessaire d'incrémenter un numéro de version quand cette propriété est marquée obsolète (dirty).

11

generated (optional - defaults to never): specifies that this property value is actually generated by the database. See the discussion of generated properties for more information.

typename peut être :

Si vous n'indiquez pas un type, Hibernate utilisera la réflexion sur le nom de la propriété pour tenter de trouver le type Hibernate correct. Hibernate essayera d'interprêter le nom de la classe retournée par le getter de la propriété en utilisant les règles 2, 3, 4 dans cet ordre. Dans certains cas vous aurez encore besoin de l'attribut type. (Par exemple, pour distinguer Hibernate.DATE et Hibernate.TIMESTAMP, ou pour préciser un type personnalisé).

L'attribut access permet de contrôler comment Hibernate accédera à la propriété à l'exécution. Par défaut, Hibernate utilisera les méthodes set/get. Si vous indiquez access="field", Hibernate ignorera les getter/setter et accédera à la propriété directement en utilisant la réflexion. Vous pouvez spécifier votre propre stratégie d'accès aux propriétés en nommant une classe qui implémente l'interface org.hibernate.propertexige une instrumentation de code d'octets build-timey.PropertyAccessor.

Les propriétés dérivées représentent une fonctionnalité particulièrement intéressante. Ces propriétés sont par définition en lecture seule, la valeur de la propriété est calculée au chargement. Le calcul est déclaré comme une expression SQL, qui se traduit par une sous-requête SELECT dans la requête SQL qui charge une instance :



<property name="totalPrice"
    formula="( SELECT SUM (li.quantity*p.price) FROM LineItem li, Product p
                WHERE li.productId = p.productId
                AND li.customerId = customerId
                AND li.orderNumber = orderNumber )"/>

Remarquez que vous pouvez référencer la propre table des entités en ne déclarant pas un alias sur une colonne particulière (customerId dans l'exemple donné). Notez aussi que vous pouvez utiliser le sous-élément de mappage <formula> plutôt que d'utiliser l'attribut si vous le souhaitez.

Une association ordinaire vers une autre classe persistante est déclarée en utilisant un élément many-to-one. Le modèle relationnel est une association de type plusieurs-à-un : une clé étrangère dans une table référence la ou les clé(s) primaire(s) dans la table cible.

<many-to-one
        name="(1)propertyName"
        column(2)="column_name"
        class=(3)"ClassName"
        cascad(4)e="cascade_style"
        fetch=(5)"join|select"
        update(6)="true|false"
        insert(6)="true|false"
        proper(7)ty-ref="propertyNameFromAssociatedClass"
        access(8)="field|property|ClassName"
        unique(9)="true|false"
        not-nu(10)ll="true|false"
        optimi(11)stic-lock="true|false"
        lazy="(12)proxy|no-proxy|false"
        not-fo(13)und="ignore|exception"
        entity(14)-name="EntityName"
        formul(15)a="arbitrary SQL expression"
        node="element-name|@attribute-name|element/@attribute|."
        embed-xml="true|false"
        index="index_name"
        unique_key="unique_key_id"
        foreign-key="foreign_key_name"
/>

1

name : le nom de la propriété.

2

column (optionnel) : le nom de la colonne de la clé étrangère. Cela peut être aussi spécifié par un ou des sous-élément(s) <column>.

3

class (optionnel - par défaut, le type de la propriété déterminé par réflexion) : le nom de la classe associée.

4

cascade (optionnel) : indique quelles opérations doivent être cascadées de l'objet parent vers l'objet associé.

5

fetch (optionnel - par défaut à select) : choisit entre le chargement de type jointure externe (outer-join) ou le chargement par select successifs.

6

update, insert (optionnel - par défaut à true) : indique que les colonnes mappées devraient être incluses dans des SQL UPDATE et/ou des déclarations INSERT. Mettre les deux à false, permet une association pure dérivée dont la valeur est initialisée à partir d'une autre propriété qui mappe à une ou plusieurs mêmes colonnes, ou par un trigger ou une autre application.

7

property-ref (optionnel) : le nom d'une propriété de la classe associée qui est jointe à cette clé étrangère. Si non-spécifiée, la clé primaire de la classe associée est utilisée.

8

access (optionnel - par défaut property) : la stratégie que doit utiliser Hibernate pour accéder aux valeurs des propriétés.

9

unique (optionnel) : génère le DDL d'une contrainte unique pour la clé étrangère. Permet aussi d'en faire la cible d'une property-ref. Cela permet de créer une véritable association un-à-un.

10

not-null (optionnel) : active le DDL d'une contrainte de nullité pour les colonnes de clés étrangères.

11

optimistic-lock (optionnel - par défaut à true) : indique si les mise à jour de cette propriété nécessitent ou non l'acquisition d'un verrou optimiste. En d'autres termes, cela détermine s'il est nécessaire d'incrémenter un numéro de version quand cette propriété est marquée obsolète (dirty).

12

lazy (optionnel - par défaut à proxy) : par défaut, les associations de point uniques utilisent des proxies. lazy="no-proxy" indique que cette propriété doit être chargée en différé au premier accès à la variable d'instance (nécessite une instrumentation du bytecode lors de la phase de construction). lazy="false" indique que l'association sera toujours chargée.

13

not-found (optionnel - par défaut = exception) : spécifie comment les clés étrangères qui référencent des lignes manquantes seront gérées : ignore traitera une ligne manquante comme une association nulle.

14

entity-name (optionnel) : le nom de l'entité de la classe associée.

15

formula (optionnel) : une expression SQL qui définit la valeur pour une clé étrangère calculée.

Setting a value of the cascade attribute to any meaningful value other than none will propagate certain operations to the associated object. The meaningful values are divided into three categories. First, basic operations, which include: persist, merge, delete, save-update, evict, replicate, lock and refresh; second, special values: delete-orphan; and third, all comma-separated combinations of operation names: cascade="persist,merge,evict" or cascade="all,delete-orphan". See Section 10.11, « Persistance transitive » for a full explanation. Note that single valued, many-to-one and one-to-one, associations do not support orphan delete.

Une déclaration many-to-one typique est aussi simple que :


<many-to-one name="product" class="Product" column="PRODUCT_ID"/>

L'attribut property-ref devrait être utilisé pour mapper seulement des données provenant d'un ancien système où les clés étrangères font référence à une clé unique de la table associée et qui n'est pas la clé primaire. C'est un cas de mauvaise conception relationnelle. Par exemple, supposez que la classe Product ait un numéro de série unique qui n'est pas la clé primaire. L'attribut unique contrôle la génération DDL par Hibernate avec l'outil SchemaExport.


<property name="serialNumber" unique="true" type="string" column="SERIAL_NUMBER"/>

Ainsi le mappage pour OrderItem peut utiliser :


<many-to-one name="product" property-ref="serialNumber" column="PRODUCT_SERIAL_NUMBER"/>

Bien que ce ne soit certainement pas encouragé.

Si la clé unique référencée comprend des propriétés multiples de l'entité associée, vous devez mapper ces propriétés à l'intérieur d'un élément nommé <properties>.

Si la clé unique référencée est la propriété d'un composant, vous pouvez spécifier le chemin de propriété :


<many-to-one name="owner" property-ref="identity.ssn" column="OWNER_SSN"/>

Une association un-à-un vers une autre classe persistante est déclarée avec l'élément one-to-one.

<one-to-one
        name="(1)propertyName"
        class=(2)"ClassName"
        cascad(3)e="cascade_style"
        constr(4)ained="true|false"
        fetch=(5)"join|select"
        proper(6)ty-ref="propertyNameFromAssociatedClass"
        access(7)="field|property|ClassName"
        formul(8)a="any SQL expression"
        lazy="(9)proxy|no-proxy|false"
        entity(10)-name="EntityName"
        node="element-name|@attribute-name|element/@attribute|."
        embed-xml="true|false"
        foreign-key="foreign_key_name"
/>

1

name : le nom de la propriété.

2

class (optionnel - par défaut, le type de la propriété déterminé par réflexion) : le nom de la classe associée.

3

cascade (optionnel) : indique quelles opérations doivent être cascadées de l'objet parent vers l'objet associé.

4

constrained (optionnel) : indique qu'une contrainte de clé étrangère sur la clé primaire de la table mappée référence la table de la classe associée. Cette option affecte l'ordre dans lequel chaque save() et chaque delete() est cascadé et détermine si l'association peut utiliser un proxy (aussi utilisé par l'outil SchemaExport).

5

fetch (optionnel - par défaut à select) : choisit entre le chargement de type jointure externe (outer-join) ou le chargement par select successifs.

6

property-ref (optionnel) : le nom de la propriété de la classe associée qui est jointe à la clé primaire de cette classe. Si ce n'est pas spécifié, la clé primaire de la classe associée est utilisée.

7

access (optionnel - par défaut property) : la stratégie que doit utiliser Hibernate pour accéder aux valeurs des propriétés.

8

formula (optionnel) : presque toutes les associations un-à-un pointent sur la clé primaire de l'entité propriétaire. Dans les rares cas différents, vous devez donner une ou plusieurs autres colonnes ou expression à joindre par une formule SQL . Voir org.hibernate.test.onetooneformula pour un exemple.

9

lazy (optionnel - par défaut proxy) : par défaut, les associations simples sont soumises à proxy. lazy="no-proxy" spécifie que la propriété doit être chargée en différé au premier accès à l'instance. (nécessite l'instrumentation du bytecode à la construction). lazy="false" indique que l'association sera toujours chargée agressivement. . Notez que si constrained="false", l'utilisation de proxy est impossible et Hibernate chargera automatiquement l'association .

10

entity-name (optionnel) : le nom de l'entité de la classe associée.

Il existe deux types d'associations un-à-un :

Les associations par clé primaire ne nécessitent pas une colonne supplémentaire en table ; si deux lignes sont liées par l'association alors les deux lignes de la table partagent la même valeur de clé primaire. Donc si vous voulez que deux objets soient liés par une association par clé primaire, vous devez faire en sorte qu'on leur assigne la même valeur d'identifiant.

Pour une association par clé primaire, ajoutez les mappages suivants à Employee et Person, respectivement :


<one-to-one name="person" class="Person"/>

<one-to-one name="employee" class="Employee" constrained="true"/>

Maintenant, vous devez faire en sorte que les clés primaires des lignes liées dans les tables PERSON et EMPLOYEE sont égales. On utilise une stratégie Hibernate spéciale de génération d'identifiants appelée foreign :


<class name="person" table="PERSON">
    <id name="id" column="PERSON_ID">
        <generator class="foreign">
            <param name="property"
>employee</param>
        </generator>
    </id>
    ...
    <one-to-one name="employee"
        class="Employee"
        constrained="true"/>
</class
>

Une instance fraîchement enregistrée de Person se voit alors assignée la même valeur de clé primaire que l'instance de Employee référencée par la propriété employee de cette Person.

Alternativement, une clé étrangère avec contrainte d'unicité de Employee vers Person peut être indiquée ainsi :


<many-to-one name="person" class="Person" column="PERSON_ID" unique="true"/>

Et cette association peut être rendue bidirectionnelle en ajoutant ceci au mappage de Person :


<one-to-one name="employee" class="Employee" property-ref="person"/>

L'élément <component> mappe les propriétés d'un objet enfant aux colonnes d'une classe parente. Les composants peuvent en retour déclarer leurs propres propriétés, composants ou collections. Voir "Components" plus bas :

<component
        name="(1)propertyName"
        class=(2)"className"
        insert(3)="true|false"
        update(4)="true|false"
        access(5)="field|property|ClassName"
        lazy="(6)true|false"
        optimi(7)stic-lock="true|false"
        unique(8)="true|false"
        node="element-name|."
>

        <property ...../>
        <many-to-one .... />
        ........
</component
>

1

name : le nom de la propriété.

2

class (optionnel - par défaut au type de la propriété déterminé par réflexion) : le nom de la classe (enfant) du composant.

3

insert : les colonnes mappées apparaissent-elles dans les SQL INSERT s ?

4

update: les colonnes mappées apparaissent-elles dans les SQL UPDATE s ?

5

access (optionnel - par défaut property) : la stratégie que doit utiliser Hibernate pour accéder aux valeurs des propriétés.

6

lazy (optionnel - par défaut à false) : indique que ce composant doit être chargé en différé au premier accès à la variable d'instance (nécessite une instrumentation du bytecode lors de la phase de construction).

7

optimistic-lock (optionnel - par défaut à true) : spécifie si les mise à jour sur ce composant nécessitent ou non l'acquisition d'un verrou optimiste. En d'autres termes, cela détermine si une incrémentation de version doit avoir lieu quand la propriété est marquée obsolète (dirty).

8

unique (optionnel - par défaut à false) : Indique qu'une contrainte d'unicité existe sur toutes les colonnes mappées de ce composant.

Les balises enfant <property> mappent les propriétés de la classe enfant sur les colonnes de la table.

L'élément <component> permet de déclarer un sous-élément <parent> qui associe une propriété de la classe composant comme une référence arrière vers l'entité contenante.

The <dynamic-component> element allows a Map to be mapped as a component, where the property names refer to keys of the map. See Section 8.5, « Les composants dynamiques » for more information.

L'élément <properties> permet la définition d'un groupement logique nommé des propriétés d'une classe. L'utilisation la plus importante de cette construction est la possibilité pour une combinaison de propriétés d'être la cible d'un property-ref. C'est aussi un moyen pratique de définir une contrainte d'unicité multi-colonnes. Par exemple :

<properties
        name="(1)logicalName"
        insert(2)="true|false"
        update(3)="true|false"
        optimi(4)stic-lock="true|false"
        unique(5)="true|false"
>

        <property ...../>
        <many-to-one .... />
        ........
</properties
>

1

name : le nom logique d'un regroupement et non le véritable nom d'une propriété.

2

insert : les colonnes mappées apparaissent-elles dans les SQL INSERT s ?

3

update: les colonnes mappées apparaissent-elles dans les SQL UPDATE s ?

4

optimistic-lock (optionnel - par défaut à true) : indique si les mise à jour sur ce composant nécessitent ou non l'acquisition d'un verrou optimiste. En d'autres termes, cela détermine si une incrémentation de version doit avoir lieu quand la propriété est marquée obsolète (dirty).

5

unique (optionnel - par défaut à false) : Indique qu'une contrainte d'unicité existe sur toutes les colonnes mappées de ce composant.

Par exemple, si nous avons le mappage de <properties> suivant :


<class name="Person">
    <id name="personNumber"/>

    ...
    <properties name="name"
            unique="true" update="false">
        <property name="firstName"/>
        <property name="initial"/>
        <property name="lastName"/>
    </properties>
</class
>

Alors nous pourrions avoir une association sur des données d'un ancien système qui font référence à cette clé unique de la table Person au lieu de la clé primaire :


<many-to-one name="person"
         class="Person" property-ref="name">
    <column name="firstName"/>
    <column name="initial"/>
    <column name="lastName"/>
</many-to-one
>

Nous ne recommandons pas une telle utilisation, en dehors du contexte de mappage de données héritées d'anciens systèmes.

Il est également possible de mapper chaque sous-classe vers sa propre table (stratégie de mappage de type table-per-subclass). L'état hérité est récupéré en joignant la table de la super-classe. L'élément <joined-subclass> est utilisé. Par exemple :

<joined-subclass
        name="(1)ClassName"
        table=(2)"tablename"
        proxy=(3)"ProxyInterface"
        lazy="(4)true|false"
        dynamic-update="true|false"
        dynamic-insert="true|false"
        schema="schema"
        catalog="catalog"
        extends="SuperclassName"
        persister="ClassName"
        subselect="SQL expression"
        entity-name="EntityName"
        node="element-name">

        <key .... >

        <property .... />
        .....
</joined-subclass
>

1

name : le nom de classe complet de la sous-classe.

2

table: le nom de la table de la sous-classe.

3

proxy (optionnel) : indique une classe ou interface à utiliser pour l'initialisation différée des proxies.

4

lazy (optionnel, par défaut à true) : spécifier lazy="false" désactive l'utilisation de l'extraction différée.

Aucune colonne discriminante n'est nécessaire pour cette stratégie de mappage. Cependant, chaque sous-classe doit déclarer une colonne de table contenant l'objet identifiant qui utilise l'élément <key>. Le mappage au début de ce chapitre serait ré-écrit ainsi :


<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
        "-//Hibernate/Hibernate Mapping DTD//EN"
        "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">

<hibernate-mapping package="eg">

        <class name="Cat" table="CATS">
                <id name="id" column="uid" type="long">
                        <generator class="hilo"/>
                </id>
                <property name="birthdate" type="date"/>
                <property name="color" not-null="true"/>
                <property name="sex" not-null="true"/>
                <property name="weight"/>
                <many-to-one name="mate"/>
                <set name="kittens">
                        <key column="MOTHER"/>
                        <one-to-many class="Cat"/>
                </set>
                <joined-subclass name="DomesticCat" table="DOMESTIC_CATS">
                    <key column="CAT"/>
                    <property name="name" type="string"/>
                </joined-subclass>
        </class>

        <class name="eg.Dog">
                <!-- mapping for Dog could go here -->
        </class>

</hibernate-mapping
>

For information about inheritance mappings see Chapitre 9, Mapping d'héritage de classe .

Une troisième option est de mapper uniquement les classes concrètes d'une hiérarchie d'héritage vers des tables, (stratégie de type table-per-concrete-class) où chaque table définit tous les états persistants de la classe, y compris les états hérités. Dans Hibernate il n'est absolument pas nécessaire de mapper explicitement de telles hiérarchies d'héritage. Vous pouvez simplement mapper chaque classe avec une déclaration <class> différente. Cependant, si vous souhaitez utiliser des associations polymorphiques (c'est-à-dire une association vers la superclasse de votre hiérarchie), vous devez utiliser le mappage <union-subclass>. Par exemple :

<union-subclass
        name="(1)ClassName"
        table=(2)"tablename"
        proxy=(3)"ProxyInterface"
        lazy="(4)true|false"
        dynamic-update="true|false"
        dynamic-insert="true|false"
        schema="schema"
        catalog="catalog"
        extends="SuperclassName"
        abstract="true|false"
        persister="ClassName"
        subselect="SQL expression"
        entity-name="EntityName"
        node="element-name">

        <property .... />
        .....
</union-subclass
>

1

name : le nom de classe complet de la sous-classe.

2

table: le nom de la table de la sous-classe.

3

proxy (optionnel) : indique une classe ou interface à utiliser pour l'initialisation différée des proxies.

4

lazy (optionnel, par défaut à true) : spécifier lazy="false" désactive l'utilisation de l'extraction différée.

Aucune colonne discriminante ou colonne clé n'est requise pour cette stratégie de mappage.

For information about inheritance mappings see Chapitre 9, Mapping d'héritage de classe .

En utilisant l'élément <join>, il est possible de mapper des propriétés d'une classe sur plusieurs tables quand il existe une relation un-à-un entre les tables. Par exemple :

<join
        table=(1)"tablename"
        schema(2)="owner"
        catalo(3)g="catalog"
        fetch=(4)"join|select"
        invers(5)e="true|false"
        option(6)al="true|false">

        <key ... />

        <property ... />
        ...
</join
>

1

table : le nom de la table jointe.

2

schema (optionnel) : surcharge le nom de schéma spécifié par l'élément racine <hibernate-mappage>.

3

catalog (optionnel) : surcharge le nom du catalogue spécifié par l'élément racine <hibernate-mappage>.

4

fetch (optionnel - par défaut à join) : si positionné à join, Hibernate utilisera une jointure interne pour charger une jointure définie par une classe ou ses super-classes et une jointure externe pour une <jointure> définie par une sous-classe. Si positionné à select, Hibernate utilisera un select séquentiel pour une <jointure> définie sur une sous-classe, qui ne sera délivrée que si une ligne représente une instance de la sous-classe. Les jointures internes seront quand même utilisées pour charger une <jointure> définie par une classe et ses super-classes.

5

inverse (optionnel - par défaut à false) : si positionné à true, Hibernate n'essaiera pas d'insérer ou de mettre à jour les propriétés définies par cette jointure.

6

optionnel (optionnel - par défaut à false) : si positionné à true, Hibernate insèrera une ligne seulement si les propriétés définies par cette jointure sont non-nulles et utilisera toujours une jointure externe pour extraire les propriétés.

Par exemple, les informations d'adresse pour une personne peuvent être mappées vers une table séparée (tout en préservant des sémantiques de type valeur pour toutes ses propriétés) :


<class name="Person"
    table="PERSON">

    <id name="id" column="PERSON_ID"
>...</id>

    <join table="ADDRESS">
        <key column="ADDRESS_ID"/>
        <property name="address"/>
        <property name="zip"/>
        <property name="country"/>
    </join>
    ...

Cette fonctionnalité est souvent seulement utile pour les modèles de données hérités d'anciens systèmes, nous recommandons d'utiliser moins de tables que de classes et un modèle de domaine à granularité fine. Cependant, c'est utile pour passer d'une stratégie de mappage d'héritage à une autre dans une hiérarchie simple, comme nous le verrons plus tard.

Nous avons rencontré l'élément <key> à plusieurs reprises maintenant. Il apparaît partout que l'élément de mappage parent définit une jointure sur une nouvelle table, et définit la clé étrangère dans la table jointe, qui référence la clé primaire de la table d'origine :

<key
        column(1)="columnname"
        on-del(2)ete="noaction|cascade"
        proper(3)ty-ref="propertyName"
        not-nu(4)ll="true|false"
        update(5)="true|false"
        unique(6)="true|false"
/>

1

column (optionnel) : le nom de la colonne de la clé étrangère. Cela peut être aussi spécifié par un ou des sous-élément(s) <column>.

2

on-delete (optionnel, par défaut à noaction) : indique si la contrainte de clé étrangère possède la possibilité au niveau base de données de suppression en cascade.

3

property-ref (optionnel) : indique que la clé étrangère fait référence à des colonnes qui ne sont pas la clé primaire de la table d'origine (Pour les données d'anciens systèmes).

4

not-null (optionnel) : indique que les colonnes des clés étrangères ne peuvent pas être nulles (c'est implicite si la clé étrangère fait partie de la clé primaire).

5

update (optionnel) : indique que la clé étrangère ne devrait jamais être mise à jour (implicite si celle-ci fait partie de la clé primaire).

6

unique (optionnel) : indique que la clé étrangère doit posséder une contrainte d'unicité (implicite si la clé étrangère est aussi la clé primaire).

Là où les suppressions doivent être performantes, nous recommandons pour les systèmes de définir toutes les clés on-delete="cascade", ainsi Hibernate utilisera une contrainte ON CASCADE DELETE au niveau base de données, plutôt que de nombreux DELETE individuels. Attention, cette fonctionnalité court-circuite la stratégie habituelle de verrou optimiste pour les données versionnées.

Les attributs not-null et update sont utiles pour mapper une association un-à-plusieurs unidirectionnelle. Si vous mappez un un-à-plusieurs unidirectionnel vers une clé étrangère non nulle, vous devez déclarer la colonne de la clé en utilisant <key not-null="true">.

Il existe encore un type de mappage de propriété. L'élément de mappage <any> définit une association polymorphique vers des classes de tables multiples. Ce type de mappage requiert toujours plus d'une colonne. La première colonne contient le type de l'entité associée. Les colonnes restantes contiennent l'identifiant. Il est impossible de spécifier une contrainte de clé étrangère pour ce type d'association, donc ce n'est certainement pas considéré comme le moyen habituel de mapper des associations (polymorphiques). Ne doit être utilisé que dans des cas particuliers (par exemple des logs d'audit, des données de session utilisateur, etc...).

L'attribut meta-type permet à l'application de spécifier un type personnalisé qui mappe des valeurs de colonnes de base de données sur des classes persistantes qui ont un attribut identifiant du type spécifié par id-type. Vous devez spécifier le mappage à partir de valeurs du méta-type sur les noms des classes.


<any name="being" id-type="long" meta-type="string">
    <meta-value value="TBL_ANIMAL" class="Animal"/>
    <meta-value value="TBL_HUMAN" class="Human"/>
    <meta-value value="TBL_ALIEN" class="Alien"/>
    <column name="table_name"/>
    <column name="id"/>
</any
>
<any
        name="(1)propertyName"
        id-typ(2)e="idtypename"
        meta-t(3)ype="metatypename"
        cascad(4)e="cascade_style"
        access(5)="field|property|ClassName"
        optimi(6)stic-lock="true|false"
>
        <meta-value ... />
        <meta-value ... />
        .....
        <column .... />
        <column .... />
        .....
</any
>

1

name : le nom de la propriété.

2

id-type : le type identifiant.

3

meta-type (optionnel - par défaut à string) : tout type permis pour un mappage par discriminateur.

4

cascade (optionnel - par défaut à none) : le style de cascade.

5

access (optionnel - par défaut property) : la stratégie que doit utiliser Hibernate pour accéder aux valeurs des propriétés.

6

optimistic-lock (optionnel - par défaut à true) : indique si les mise à jour sur cette propriété nécessitent ou non l'acquisition d'un verrou optimiste. En d'autres termes, définit si un incrément de version doit avoir lieu quand cette propriété est marquée dirty.

Pour le service de persistance, les objets sont classés en deux groupes au niveau langage Java :

Une entité existe indépendamment de tout autre objet possédant des références vers l'entité. Comparez cela avec le modèle Java habituel où un objet est supprimé par le garbage collector dès qu'il n'est plus référencé. Les entités doivent être explicitement enregistrées et supprimées (sauf dans les cas où sauvegardes et suppressions sont cascadées d'une entité parent vers ses enfants). C'est différent du modèle ODMG de persistance par atteignabilité - et correspond mieux à la façon dont les objets sont habituellement utilisés dans des grands systèmes. Les entités permettent les références circulaires et partagées. Elles peuvent aussi être versionnées.

L'état persistant d'une entité consiste en des références vers d'autres entités et instances de types valeurs. Ces valeurs sont des types primitifs, des collections (et non le contenu d'une collection), des composants de certains objets immuables. Contrairement aux entités, les valeurs (et en particulier les collections et composants) sont persistées et supprimées par atteignabiliité. Comme les valeurs (et types primitifs) sont persistées et supprimées avec l'entité qui les contient, ils ne peuvent pas posséder leurs propres versions. Les valeurs n'ont pas d'identité indépendantes, ainsi elles ne peuvent pas être partagées par deux entités ou collections.

Jusqu'à présent nous avons utilisé le terme "classe persistante" pour parler d'entités. Nous allons continuer à faire ainsi. Cependant, au sens strict, toutes les classes définies par un utilisateur possédant un état persistant ne sont pas des entités. Un composant est une classe définie par un utilisateur avec la sémantique d'une valeur. Une propriété Java de type java.lang.String a aussi les caractéristiques d'une valeur. Selon cette définition, nous sommes en mesure de déclarer que tous les types (classes) fournis par JDK possèdent la sémantique d'une valeur dans Java, alors que les types définis par un utilisateur pourront être mappés avec des sémantiques entités ou valeur type. Cette décision est prise par le développeur d'application. Un bon conseil pour une classe entité dans un modèle de domaine sont des références partagées à une instance unique de cette classe, alors que la composition ou l'agrégation se traduit en général par une valeur type.

Nous nous pencherons sur ces deux concepts tout au long de la documentation.

Le défi est de mapper les types Javas (et la définition des développeurs des entités et valeurs types) sur les types du SQL ou des bases de données. Le pont entre les deux systèmes est proposé par Hibernate : pour les entités nous utilisons <class>, <subclass> et ainsi de suite. Pour les types valeurs nous utilisons <property>, <component>, etc., habituellement avec un attribut type. La valeur de cet attribut est le nom d'un type de mappage Hibernate. Hibernate propose de nombreux mappages prêts à l'utilisation (pour les types de valeurs standards du JDK). Vous pouvez écrire vos propres types de mappages et implémenter aussi vos propres stratégies de conversion comme nous le verrons plus tard.

Tous les types proposés Hibernate à part les collections autorisent les sémantiques null.

Les types de mappage de base peuvent être classés de la façon suivante :

integer, long, short, float, double, character, byte, boolean, yes_no, true_false

Les mappages de type des primitives Java ou leurs classes wrappers (ex : Integer pour int) vers les types de colonne SQL (propriétaires) appropriés. boolean, yes_noet true_false sont tous des alternatives pour les types Java boolean ou java.lang.Boolean.

string

Mappage de type de java.lang.String vers VARCHAR (ou le VARCHAR2 Oracle).

date, time, timestamp

mappages de type pour java.util.Date et ses sous-classes vers les types SQL DATE, TIME et TIMESTAMP (ou équivalent).

calendar, calendar_date

mappages de type pour java.util.Calendar vers les types SQL TIMESTAMP et DATE (ou équivalent).

big_decimal, big_integer

mappages de type de java.math.BigDecimal et java.math.BigInteger vers NUMERIC (ou le NUMBER Oracle).

locale, timezone, currency

mappages de type pour java.util.Locale, java.util.TimeZone et java.util.Currency vers VARCHAR (ou le VARCHAR2 Oracle). Les instances de Locale et Currency sont mappées sur leurs codes ISO. Les instances de TimeZone sont mappées sur leur ID.

class

Un type de mappage de java.lang.Class vers VARCHAR (ou le VARCHAR2 Oracle). Un objet Class est mappé sur son nom Java complet.

binary

Mappe les tableaux de bytes vers le type binaire SQL approprié.

text

Mappe les longues chaînes de caractères Java vers les types SQL CLOB ou TEXT.

serializable

Mappe les types Java sérialisables vers le type SQL binaire approprié. Vous pouvez aussi indiquer le type Hibernate serializable avec le nom d'une classe Java sérialisable ou une interface qui ne soit pas par défaut un type de base.

clob, blob

Mappages de type pour les classes JDBC java.sql.Clob et java.sql.Blob. Ces types peuvent ne pas convenir pour certaines applications car un objet blob ou clob peut ne pas être réutilisable en dehors d'une transaction (de plus l'implémentation par les pilotes comporte des lacunes).

imm_date, imm_time, imm_timestamp, imm_calendar, imm_calendar_date, imm_serializable, imm_binary

Mappages de type pour ceux qui sont habituellement considérés comme des types Java modifiables, et pour lesquels Hibernate effectue certaines optimisations convenant seulement aux types Java immuables. L'application les traite comme immuables. Par exemple, vous ne devriez pas appeler Date.setTime() sur une instance mappée sur un imm_timestamp. Pour changer la valeur de la propriété, et faire en sorte que cette modification soit persistée, l'application doit assigner un nouvel (non identique) objet à la propriété.

Les identifiants uniques des entités et collections peuvent être de n'importe quel type de base excepté binary, blob et clob (les identifiants composites sont aussi permis, voir plus bas).

Les types de base des valeurs ont des Type constants correspondants et définis dans org.hibernate.Hibernate. Par exemple, Hibernate.STRING représente le type string.

Il est assez facile pour les développeurs de créer leurs propres types de valeurs. Par exemple, vous aimeriez persister des propriétés du type java.lang.BigInteger dans des colonnes VARCHAR. Hibernate ne procure pas de type par défaut à cet effet. Toutefois, les types personnalisés ne se limitent pas à mapper des propriétés (ou élément collection) à une simple colonne de table. Donc, par exemple, vous pourriez avoir une propriété Java getName()/setName() de type java.lang.String persistée dans les colonnes FIRST_NAME, INITIAL, SURNAME.

Pour implémenter votre propre type, vous pouvez soit implémenter org.hibernate.UserType soit org.hibernate.CompositeUserType et déclarer des propriétés utilisant des noms de classes complets du type. Consultez org.hibernate.test.DoubleStringType pour étudier les possibilités.


<property name="twoStrings" type="org.hibernate.test.DoubleStringType">
    <column name="first_string"/>
    <column name="second_string"/>
</property
>

Remarquez l'utilisation des balises <column> pour mapper une propriété sur des colonnes multiples.

Les interfaces CompositeUserType, EnhancedUserType, UserCollectionType, et UserVersionType prennent en charge des utilisations plus spécialisées.

Vous pouvez même fournir des paramètres en indiquant UserType dans le fichier de mappage. À cet effet, votre UserType doit implémenter l'interface org.hibernate.usertype.ParameterizedType. Pour spécifier des paramètres dans votre type propre, vous pouvez utiliser l'élément <type> dans vos fichiers de mappage.


<property name="priority">
    <type name="com.mycompany.usertypes.DefaultValueIntegerType">
        <param name="default"
>0</param>
    </type>
</property
>

Le UserType permet maintenant de récupérer la valeur pour le paramètre nommé default à partir de l'objet Properties qui lui est passé.

Si vous utilisez fréquemment un UserType, il est utile de lui définir un nom plus court. Vous pouvez l'effectuer, en utilisant l'élément <typedef>. Les typedefs permettent d'assigner un nom à votre type propre et peuvent aussi contenir une liste de valeurs de paramètres par défaut si ce type est paramétré.


<typedef class="com.mycompany.usertypes.DefaultValueIntegerType" name="default_zero">
    <param name="default"
>0</param>
</typedef
>

<property name="priority" type="default_zero"/>

Il est également possible de redéfinir les paramètres par défaut du typedef au cas par cas en utilisant des paramètres type sur le mappage de la propriété.

Alors que Hibernate offre une riche variété de types, et la prise en charge des composants, vous aurez très rarement besoin d'utiliser un type personnalisé, il est néanmoins recommandé d'utiliser des types personnalisés pour les classes (non entités) qui apparaissent fréquemment dans votre application. Par exemple, une classe MonetaryAmount est un bon candidat pour un CompositeUserType même si elle pourrait facilement être mappée en tant que composant. Une motivation pour cela est l'abstraction. Avec un type personnalisé, vos documents de mappage sont à l'abri des changements futurs dans votre façon de représenter des valeurs monétaires.

Il est possible de fournir plus d'un mappage par classe persistante. Dans ce cas, vous devez spécifier un nom d'entité pour lever l'ambiguité entre les instances des entités mappées (par défaut, le nom de l'entité est celui de la classe). Hibernate vous permet de spécifier le nom de l'entité lorsque vous utilisez des objets persistants, lorsque vous écrivez des requêtes ou quand vous mappez des associations vers les entités nommées.

<class name="Contract" table="Contracts"
        entity-name="CurrentContract">
    ...
    <set name="history" inverse="true"
            order-by="effectiveEndDate desc">
        <key column="currentContractId"/>
        <one-to-many entity-name="HistoricalContract"/>
    </set>
</class>

<class name="Contract" table="ContractHistory"
        entity-name="HistoricalContract">
    ...
    <many-to-one name="currentContract"
            column="currentContractId"
            entity-name="CurrentContract"/>
</class
>

Remarquez comment les associations sont désormais spécifiées en utilisant entity-name au lieu de class.

Vous pouvez forcer Hibernate à mettre un identifiant entre quotes dans le SQL généré en mettant le nom de la table ou de la colonne entre backticks dans le document de mappage. Hibernate utilisera les bons styles de quotes pour le SQL Dialect (habituellement des doubles quotes, mais des parenthèses pour SQL Server et des backticks pour MySQL).


<class name="LineItem" table="`Line Item`">
    <id name="id" column="`Item Id`"/><generator class="assigned"/></id>
    <property name="itemNumber" column="`Item #`"/>
    ...
</class
>

XML ne convient pas à tout le monde, il y a donc des moyens alternatifs pour définir des métadonnées de mappage O/R dans Hibernate.

De nombreux utilisateurs de Hibernate préfèrent embarquer les informations de mappages directement au sein du code source en utilisant lesbalises XDoclet @hibernate.tags. Nous ne couvrons pas cette approche dans ce document puisque cela est considéré comme faisant partie de XDoclet. Cependant, nous présentons l'exemple suivant de la classe Cat avec des mappages XDoclet :

package eg;

import java.util.Set;
import java.util.Date;
/**
 * @hibernate.class
 *  table="CATS"
 */
public class Cat {
    private Long id; // identifier
    private Date birthdate;
    private Cat mother;
    private Set kittens
    private Color color;
    private char sex;
    private float weight;
    /*
     * @hibernate.id
     *  generator-class="native"
     *  column="CAT_ID"
     */
    public Long getId() {
        return id;
    }
    private void setId(Long id) {
        this.id=id;
    }
    /**
     * @hibernate.many-to-one
     *  column="PARENT_ID"
     */
    public Cat getMother() {
        return mother;
    }
    void setMother(Cat mother) {
        this.mother = mother;
    }
    /**
     * @hibernate.property
     *  column="BIRTH_DATE"
     */
    public Date getBirthdate() {
        return birthdate;
    }
    void setBirthdate(Date date) {
        birthdate = date;
    }
    /**
     * @hibernate.property
     *  column="WEIGHT"
     */
    public float getWeight() {
        return weight;
    }
    void setWeight(float weight) {
        this.weight = weight;
    }
    /**
     * @hibernate.property
     *  column="COLOR"
     *  not-null="true"
     */
    public Color getColor() {
        return color;
    }
    void setColor(Color color) {
        this.color = color;
    }
    /**
     * @hibernate.set
     *  inverse="true"
     *  order-by="BIRTH_DATE"
     * @hibernate.collection-key
     *  column="PARENT_ID"
     * @hibernate.collection-one-to-many
     */
    public Set getKittens() {
        return kittens;
    }
    void setKittens(Set kittens) {
        this.kittens = kittens;
    }
    // addKitten not needed by Hibernate
    public void addKitten(Cat kitten) {
        kittens.add(kitten);
    }
    /**
     * @hibernate.property
     *  column="SEX"
     *  not-null="true"
     *  update="false"
     */
    public char getSex() {
        return sex;
    }
    void setSex(char sex) {
        this.sex=sex;
    }
}

Voyez le site web de Hibernate pour plus d'exemples sur XDoclet et Hibernate.

Le JDK 5.0 introduit des annotations proches de celles de XDoclet au niveau java, qui sont type-safe et vérifiées à la compilation. Ce mécanisme est plus puissant que XDoclet et mieux supporté par les outils et les IDE. IntelliJ IDEA, par exemple, supporte l'auto-complétion et le surlignement syntaxique des annotations JDK 5.0. La nouvelle révision des spécifications des EJB (JSR-220) utilise les annotations JDK 5.0 comme mécanisme primaire pour les metadonnées des beans entités. Hibernate3 implémente l'EntityManager de la JSR-220 (API de persistance), le support du mappage de métadonnées est disponible via le paquetage Hibernate Annotations, en tant que module séparé à télécharger. EJB3 (JSR-220) et les métadonnées Hibernate3 sont supportés.

Ceci est un exemple d'une classe POJO annotée comme un EJB entité :

@Entity(access = AccessType.FIELD)

public class Customer implements Serializable {
    @Id;
    Long id;
    String firstName;
    String lastName;
    Date birthday;
    @Transient
    Integer age;
    @Embedded
    private Address homeAddress;
    @OneToMany(cascade=CascadeType.ALL)
    @JoinColumn(name="CUSTOMER_ID")
    Set<Order
> orders;
    // Getter/setter and business methods
}

Les propriétés générées sont des propriétés dont les valeurs sont générées par la base de données. Typiquement, les applications Hibernate avaient besoin d'invoquer refresh sur les instances qui contenaient des propriétés pour lesquelles la base de données générait des valeurs. Marquer les propriétés comme générées, permet à l'application de déléguer cette responsabilité à Hibernate. Principalement, à chaque fois que Hibernate réalise un SQL INSERT ou UPDATE en base de données pour une entité marquée comme telle, cela provoque immédiatement un select pour récupérer les valeurs générées.

Properties marked as generated must additionally be non-insertable and non-updateable. Only versions, timestamps, and simple properties, can be marked as generated.

never (par défaut) - indique que la valeur donnée de la propriété n'est pas générée dans la base de données.

insert: the given property value is generated on insert, but is not regenerated on subsequent updates. Properties like created-date fall into this category. Even though version and timestamp properties can be marked as generated, this option is not available.

always - indique que la valeur de la propriété est générée à l'insertion comme aux mise à jour.

Hibernate allows you to customize the SQL it uses to read and write the values of columns mapped to simple properties. For example, if your database provides a set of data encryption functions, you can invoke them for individual columns like this:

<!-- XML : generated by JHighlight v1.0 (http://jhighlight.dev.java.net) -->
<span class="xml_tag_symbols">&lt;</span><span class="xml_tag_name">property</span><span class="xml_plain">&nbsp;</span><span class="xml_attribute_name">name</span><span class="xml_tag_symbols">=</span><span class="xml_attribute_value">&quot;creditCardNumber&quot;</span><span class="xml_tag_symbols">&gt;</span><span class="xml_plain"></span><br />
<span class="xml_plain">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="xml_tag_symbols">&lt;</span><span class="xml_tag_name">column</span><span class="xml_plain">&nbsp;</span><br />
<span class="xml_plain">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="xml_attribute_name">name</span><span class="xml_tag_symbols">=</span><span class="xml_attribute_value">&quot;credit_card_num&quot;</span><span class="xml_plain"></span><br />
<span class="xml_plain">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="xml_attribute_name">read</span><span class="xml_tag_symbols">=</span><span class="xml_attribute_value">&quot;decrypt(credit_card_num)&quot;</span><span class="xml_plain"></span><br />
<span class="xml_plain">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="xml_attribute_name">write</span><span class="xml_tag_symbols">=</span><span class="xml_attribute_value">&quot;encrypt(?)&quot;</span><span class="xml_tag_symbols">/&gt;</span><span class="xml_plain"></span><br />
<span class="xml_tag_symbols">&lt;/</span><span class="xml_tag_name">property</span><span class="xml_plain"></span><br />
<span class="xml_tag_symbols">&gt;</span><span class="xml_plain"></span><br />

Hibernate applies the custom expressions automatically whenever the property is referenced in a query. This functionality is similar to a derived-property formula with two differences:

  • The property is backed by one or more columns that are exported as part of automatic schema generation.

  • The property is read-write, not read-only.

The write expression, if specified, must contain exactly one '?' placeholder for the value.

Permettent les ordres CREATE et DROP d'objets arbitraire de la base de données, en conjonction avec les outils Hibernate d'évolutions de schéma, pour permettre de définir complètement un schéma utilisateur au sein des fichiers de mappage Hibernate. Bien que conçu spécifiquement pour créer et supprimer des objets tels que les triggers et les procédures stockées, en réalité toute commande pouvant être exécutée via une méthode de java.sql.Statement.execute() (ALTERs, INSERTS, etc) est valable à cet endroit. Il y a principalement deux modes pour définir les objets auxiliaires de base de données :

Le premier mode est de lister explicitement les commandes CREATE et DROP dans le fichier de mappage :


<hibernate-mapping>
    ...
    <database-object>
        <create
>CREATE TRIGGER my_trigger ...</create>
        <drop
>DROP TRIGGER my_trigger</drop>
    </database-object>
</hibernate-mapping
>

Le second mode est de fournir une classe personnalisée qui sait comment construire les commandes CREATE et DROP. Cette classe personnalisée doit implémenter l'interface org.hibernate.mappage.AuxiliaryDatabaseObject.


<hibernate-mapping>
    ...
    <database-object>
        <definition class="MyTriggerDefinition"/>
    </database-object>
</hibernate-mapping
>

De plus, ces objets de base de données peuvent être optionnellement traités selon l'utilisation de dialectes particuliers.


<hibernate-mapping>
    ...
    <database-object>
        <definition class="MyTriggerDefinition"/>
        <dialect-scope name="org.hibernate.dialect.Oracle9iDialect"/>
        <dialect-scope name="org.hibernate.dialect.Oracle10gDialect"/>
    </database-object>
</hibernate-mapping
>