IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Hibernate Java Discussion :

Gérer des schémas multiples avec Hibernate


Sujet :

Hibernate Java

  1. #1
    Rédacteur
    Avatar de romaintaz
    Homme Profil pro
    Java craftsman
    Inscrit en
    Juillet 2005
    Messages
    3 790
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 45
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : Java craftsman
    Secteur : Finance

    Informations forums :
    Inscription : Juillet 2005
    Messages : 3 790
    Points : 7 275
    Points
    7 275
    Par défaut Gérer des schémas multiples avec Hibernate
    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.
    Nous sommes tous semblables, alors acceptons nos différences !
    --------------------------------------------------------------
    Liens : Blog | Page DVP | Twitter
    Articles : Hudson | Sonar | Outils de builds Java Maven 3 | Play! 1 | TeamCity| CitConf 2009
    Critiques : Apache Maven

  2. #2
    Membre régulier
    Profil pro
    Inscrit en
    Novembre 2009
    Messages
    82
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2009
    Messages : 82
    Points : 82
    Points
    82
    Par défaut
    Je pense qu'en utilisant le "Mapping inheritance" comme tu le fais, en utilisant le "Single table per class hierarchy" au lieu de "Inherit properties from superclasses" , ça devrait marcher :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
     
    @Entity
    @Inheritance(strategy=InheritanceType.SINGLE_TABLE)
    @DiscriminatorColumn(
        name="planetype",
        discriminatorType=DiscriminatorType.STRING
    )
    @DiscriminatorValue("Plane")
    public class Plane { ... }
     
    @Entity
    @DiscriminatorValue("A320")
    public class A320 extends Plane { ... }

    http://docs.jboss.org/hibernate/stab...single/#d0e829
    Code Poet

  3. #3
    Modérateur
    Avatar de OButterlin
    Homme Profil pro
    Inscrit en
    Novembre 2006
    Messages
    7 310
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Novembre 2006
    Messages : 7 310
    Points : 9 522
    Points
    9 522
    Billets dans le blog
    1
    Par défaut
    (je ne suis pas sûr d'avoir tout compris mais je te propose ceci )
    Je pense qu'il serait plus simple d'avoir l'équivalent du "mandant" d'SAP... en d'autres termes, un cloisonnement logique des données.
    Dans les tables impactées, tu rajoutes une colonne (on l'appellera DB_LOGIQUE par exemple) et tu filtres tes requêtes sur l'id de la DB logique (à priori liée à l'utilisateur).
    C'est un peu ce qui est utilisé pour cloisonner par filiales, chacun ne voyant que la sienne...

    Mais comme dit en préambule, je ne suis pas sûr d'avoir tout compris...
    N'oubliez pas de consulter les FAQ Java et les cours et tutoriels Java

  4. #4
    Membre régulier
    Profil pro
    Inscrit en
    Novembre 2009
    Messages
    82
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2009
    Messages : 82
    Points : 82
    Points
    82
    Par défaut
    Désolé j ai pas pris en compte "au runtime de l'application, ce schéma peut changer."
    Code Poet

Discussions similaires

  1. BD multiples avec hibernate
    Par fahsinet dans le forum Hibernate
    Réponses: 1
    Dernier message: 10/02/2009, 20h51
  2. Gérer des attributs "value" avec Javascript
    Par Jarodd dans le forum Général JavaScript
    Réponses: 40
    Dernier message: 14/11/2008, 12h44
  3. gestion des Schema oracle avec hibernate
    Par fbo1276 dans le forum Hibernate
    Réponses: 2
    Dernier message: 19/11/2007, 17h53
  4. Gérer des déploiement différents avec Maven.
    Par martopioche dans le forum Maven
    Réponses: 5
    Dernier message: 02/10/2007, 12h28
  5. Comment gérer des sous ensembles avec des "enum" ?
    Par ogattaz dans le forum Langage
    Réponses: 2
    Dernier message: 30/05/2007, 10h29

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo