Bonjour à tous !
J'ai un problème que je n'arrive pas à résoudre depuis quelques jours concernant un "double mapping" de table.
Tout d'abord, ma version d'hibernate : je travaille avec hibernate v3.
Mon contexte : pour simplifier, on va prendre un exemple de structure arborescente :
- Une entité A possède plusieurs entités B
- Une entité B référence une entité A et possède plusieurs entités C
- Une entité C référence une entité B
D'un point de vu "tables" j'aurai un idA dans B, et un idB dans C.
Coté hibernate, j'ai décidé de faire un mapping double pour mes tables, pour "contrôler" le lazy loading. Je m'explique : dans mon application, je sais pertinament que je partirai :
- "soit du bas" (en l'occurence C) pour "remonter" (vers A)
- "soit du haut" (en l'occurence A) pour "descendre" (vers C)
=> Jamais je n'aurai besoin de faire "d'aller retour" dans ma hiérarchie (monter puis redescendre par exemple)
Ce que je ne veux pas : charger systématiquement tous mes "fils" lorsque je n'en ai pas envie (typiquement, lorsque je pars de C vers A, je me fiche de connaître tous les fils du B que je référence, ainsi que de tous les fils du A que B référence).
Je suis donc arrivé à l'issue suivante :
- Définir une classe abstraite "AbstractX" qui va contenir uniquement les données de ma table X, hors relations (= sans références vers les autres entités)
- Définir une sous-classe de "AbstractX" : "LaziedX" qui va avoir une référence vers ma classe père "Lazied" (par exemple, dans LaziedC, j'aurai une référence à LaziedB). Cette association many-to-one sera en lazy="false".
- Définir une sous classe de "AbstractX" : "NotLaziedX" qui va avoir une référence vers tous les fils "NotLazied" (par exemple, dans NotLaziedB, j'aurai une référence à tous les NotLaziedC, fils de NotLaziedB). Cette association one-to-many sera en lazy="false"
Après, dans mon tier données, je n'aurai qu'à faire appel à un get(NotLaziedA.class) ou un get(LaziedC) pour avoir mon arborescence construite d'une façon optimisée "dans le sens que je veux"
"Théoriquement" tout cela a l'air de bien fonctionner !
Maintenant, dans la pratique, j'ai un problème de discriminator.
J'utilise la stratégie "une table par hiérarchie" qui colle tout à fait à mon contexte. Le problème est que je dois définir un discriminator dans ma classe abstraite et une discriminator-value pour chaque <subclass>.
Le mieux du mieux serait de récupérer soit le "nom de table" soit le "nom de classe" courant (à l'aide d'une fonction hql par exemple). Ce serait un discriminator parfait pour mon cas de figure.
Maintenant, lorsque je regarde
ici je vois que, dans l'exemple, est utilisée une formula :
Code:
<discriminator
formula="case when CLASS_TYPE in ('a', 'b', 'c') then 0 else 1 end"
type="integer"/>
Chez moi, lorsque j'utilise "CLASS_TYPE", hibernate rajoute le nom de table devant et cherche cette colonne dans la table (chose que je n'ai pas !) : j'en ai donc déduis que ce n'était qu'un exemple et pas une fonction/mot clef HQL réservé :/
A votre avis, ma conception est-elle complètement foireuse ?
Si non, pensez-vous qu'il soit possible de m'en sortir à l'aide d'une fonction hql sans avoir à modifier mon modèle pour rajouter une colonne discriminante (ce qui d'ailleurs ne résoudrait pas le problème) ?
J'ai tenté de mettre un discriminant "bidon" type :
Code:
<discriminator insert="false" formula="'xxx'"/>
en mettant des discriminator-value à xxx et cela ne marche pas mieux (en fait hibernate "fonctionne" mais ne me retourne rien lorsque je fais un find() sans passer de critères)
Cela me paraît tout de même bizarre qu'hibernate ne permette pas de faire de l'héritage "objet" (puisqu'au final, c'est ce que je veux faire :)) et se cantonne uniquement à un héritage "relationnel" (ce qui, c'est vrai, est le principal besoin généralement, mais pas dans mon cas !)
En effet, une solution à mon problème serait de ne pas utiliser le tag <subclass> qui m'impose l'utilisation de discriminator, et ainsi de "copier coller" les champs de mon AbstractX dans mes LaziedX et NotLaziedX. Mais bon, le copier coller, je n'aime pas !
Merci d'avance à celles et ceux qui voudront bien se pencher sur mon problème :)
EDIT:
J'attache un exemple de mon fichier B.hbm.xml ;)
Code:
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping
PUBLIC "-//Hibernate/Hibernate Mapping DTD//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="mypackage.AbstractB" table="B" abstract="true">
<id name="id" type="java.lang.Long" unsaved-value="-1">
<column name="idB"/>
<generator class="native"/>
</id>
<discriminator formula="'lazy'" type="string" />
<property name="name" type="string" update="false" insert="true" length="255">
<column name="name" not-null="true"/>
</property>
</class>
<subclass name="mypackage.LaziedB"
extends="mypackage.AbstractB"
discriminator-value="lazy">
<many-to-one name="A" class="mypackage.LaziedA" fetch="select" lazy="false">
<column name="idA" not-null="false"/>
</many-to-one>
</subclass>
<subclass name="mypackage.NotLaziedB" extends="mypackage.AbstractB"
discriminator-value="notlazy">
<property name="idA" type="long" update="false" insert="true">
<column name="idA" not-null="false" />
</property>
<set name="Cs" lazy="false" inverse="true">
<key column="idB" />
<one-to-many class="mypackage.NotLaziedC"/>
</set>
</subclass>
</hibernate-mapping>