Bonjour,

J'ai une application qui utilise Spring 2.5.2 et Hibernate 3.2.6 pour la connexion à la base de données.
Je dois me connecter à un schéma précis sur ma bases de données, mais au runtime de l'application, ce schéma peut changer. Mais quoiqu'il en soit, je ne me connecte jamais qu'à un seul schéma à la fois (ouf !)

Les tables et colonnes sur lesquels je travaille existent dans tous les schémas accessibles, mais pas forcément sous les mêmes noms, en particulier pour les tables, qui n'ont jamais le même nom !

Globalement, j'ai réussi à peu près à m'en sortir, mais je trouve l'ensemble très fastidieux, car il y a énormément de redondances.

Prennons un exemple plus concret. Je dois gérer des débiteurs (debtors), j'ai donc une table T_DEBTOR.
Si on se limite à 2 schémas (mais dans mon application, je serais plutôt entre 5 et 20), je vais donc avoir 2 tables : T_DEBTOR_ONE et T_DEBTOR_TWO.

Dans mon code Java, idéalement, je souhaiterais n'avoir qu'à gérer une classe, Debtor.
Comme je travaille avec Hibernate annotations, je dois toutefois créer des sous classes : DebtorOne et DebtorTwo, chacune correspondant à une entité dans le schéma correspondant.

Voici en gros ce que donne le code Java de ma classe mère (j'utilise l'annotation @MappedSuperclass) :

Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
 
@MappedSuperclass
public class Debtor {
 
    @Id
    @Column(name = "IDDEBTOR")
    protected String idDebtor; // Avec les getter et setter
 
    ...
 
}
Et dans ma classe DebtorOne (qui sera pareil que DebtorTwo) :

Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
 
@Entity
@Table(name = "DEBTOR_ONE")
public class DebtorOne extends Debtor {
 
...
Maintenant, du côté de mon DAO, je veux récupérer l'ensemble des debtors. Une requête de ce type ne fonctionnera pas :

Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
 
public List<Debtor> findAllDebtors() {
    return (List<Debtor>) em.createQuery("select d from Debtor d").getResultList();
}
En effet, vu comme ça, Hibernate se plaind de ne pas connaître l'entité Debtor.
Du coup, je suis obligé de tricher en créant dans mes entités des NamedQueries :

Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
 
@Entity
@Table(name = "T_DEBTOR_ONE")
@NamedNativeQueries( { @NamedNativeQuery(name = "findAllDebtors", query = "select d from DebtorOne d") })
public class DebtorOne implements Debtor {
    ...
(pour être tout à fait exact, les noms des NamedQueries varient selon le schéma de destination, mais ça, j'arrive à le gérer sans problème)

Du coup, dans mon DAO, j'ai ceci :

Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
 
@SuppressWarnings("unchecked")
public List<Debtor> findAllDebtors() {
    Query q = em.createNamedQuery("findAllDebtors");
    return (List<Debtor>) q.getResultList();
}
Alors là, ça marche, même si c'est moyennement beau.

Mais les choses se corsent maintenant si je veux persister un object dans mon DAO :

Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
 
@Transactional
public void save(Debtor debtor) {
    em.persist(debtor);
}
Là, j'ai un problème :

Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
 
// Ce code marche
Debtor one = new DebtorOne();
debtorDao.save(one);
// Celui-là non !
Debtor two = new Debtor();
debtorDao.save(two);

J'ai pensé à quelques pistes pour résoudre ce problème :

1. Créer des factories, de façons à faire ceci :

Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
 
Debtor one = new DebtorFactory.createDebtor();
// Ici, one pourrait être un DebtorOne ou un DebtorTwo, mais pas un Debtor "tout court" et donc Hibernate serait content !
debtorDao.save(one);
Ca devrait marcher mais c'est vraiment lourd je trouve de trainer toutes ces usines...

2. Oublier les annotations et passer par la configuration XML. En effet, si au changement du schéma je recharge également toute ma configuration XML, je devrais pouvoir m'en sortir avec les classes de bases (i.e. Debtor uniquement, sans les DebtorXXX).

3. Idéalement, j'aimerais pouvoir changer les paramètres des annotations Hibernate au runtime. Ainsi, avoir juste une classe Debtor :

Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
 
@Entity
@Table(name = "La magie intervient ici")
@NamedNativeQueries( { @NamedNativeQuery(name = "findAllDebtors", query = "select d from Debtor d") })
public class Debtor {
    ...

Mes questions :

Que pensez-vous de ma façon de résoudre le problème ?
Comment faire pour rendre les choses plus faciles ?
Puis-je m'en sortir simplement en conservant les Hibernate annotations, ou dois-je absolument passer par la configuration XML.


Merci d'avance.