Hibernate n’aime pas la discrimination

Travailler sur des applications legacy nous amène parfois à faire face à des difficultés qui nous gênent dans la mise en place d’outils modernes tout en conservant le modèle existant.
Cela m’est arrivé récemment lorsque j’ai du mapper une table de jointure un peu spéciale sur un projet de portage.

Cette table, qu’on appellera USERLINK permet d’associer un object User soit avec une Company soit avec un BankAccount. Dans la table, on a une colonne LINKTYPE qui permet justement de savoir de quel type est l’association.

Jusque là tout va bien, on choisit la stratégie Hibernate “Table per class hierarchy” et on utilise la colonne LINKTYPE comme discriminant. On obtient alors un fichier de mapping de ce genre :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<class name="com.excilys.labs.model.UserGenericLink" table="USERLINK" abstract="true" discriminator-value="-1">
    <id name="id">
        <column name="IDUSERLINK" not-null="true"/>
        [...]
    </id>

    <discriminator column="LINKTYPE" type="integer" not-null="true"/>

    <many-to-one name="user">
        <column name="IDUSER" not-null="true"/>
    </many-to-one>

    <subclass name="com.excilys.labs.model.UserToCompanyLink" discriminator-value="0">
        <many-to-one name="company" class="com.excilys.labs.model.Company">
            <column name="IDOBJECT" not-null="true"/>
        </many-to-one>
    </subclass>

    <subclass name="com.excilys.labs.model.UserToBankAccountLink" discriminator-value="1">
        <many-to-one name="bankAccount" class="com.excilys.labs.model.BankAccount">
            <column name="IDOBJECT" not-null="true"/>
        </many-to-one>
    </subclass>
</class>

De l’autre coté, dans le mapping de la classe User on rajoute les sets qui vont bien :

1
2
3
4
5
6
7
8
9
10
11
12
<set name="companyLinks" inverse="true" embed-xml="false" cascade="save-update, delete, delete-orphan" >
    <key>
        <column name="IDUSER" not-null="true"/>
    </key>
    <one-to-many class="com.excilys.labs.model.UserToCompanyLink"/>
</set>
<set name="bankAccountsLinks" inverse="true" embed-xml="false" cascade="save-update, delete, delete-orphan" >
    <key>
        <column name="IDUSER" not-null="true"/>
    </key>
    <one-to-many class="com.excilys.labs.model.UserToBankAccountLink"/>
</set>

Tout ça ne semble pas trop mal, Hibernate a maintenant toutes les informations dont il a besoin, et pourtant…
Lorsqu’on essaye de récupérer tous les liens d’un utilisateur vers ses sociétés :

1
Set<UserToCompanyLink> companyLinks = user.getCompanyLinks();

on récupère un Set qui contient plus d’objets que prévu.

Pour comprendre ce qui se passe on active les logs Hibernate et on se rend compte que ce dernier omet tout simplement d’utiliser le discriminant (pas de “WHERE LINKTYPE=?” dans les requêtes).
Un petit tour dans la doc Hibernate et on trouve notre parade :

1
<discriminator column="LINKTYPE" force="true" type="integer" not-null="true"/>

En effet dans ce cas particulier, “mapping d’une association dont le type est mappé avec un discriminant”, il est nécessaire de forcer l’utilisation de ce dernier avec le paramètre force=”true”.

Bug Hibernate ou mauvaise modélisation, dans tous les cas il n’est pas naturel de devoir forcer l’utilisation du discriminant. Certains se sont déjà posés la question mais je n’ai pas un avis tranché à ce jour. Et vous, qu’en pensez vous ?

VN:R_U [1.9.22_1171]
Rating: 0 (from 0 votes)
Share
Ce contenu a été publié dans Non classé, avec comme mot(s)-clef(s) , . Vous pouvez le mettre en favoris avec ce permalien.

Laisser un commentaire