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 :

[Hibernate] Pattern décorateur : stratégie de sauvegarde/chargement


Sujet :

Hibernate Java

  1. #1
    Membre régulier
    Profil pro
    Inscrit en
    Avril 2004
    Messages
    56
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2004
    Messages : 56
    Points : 77
    Points
    77
    Par défaut [Hibernate] Pattern décorateur : stratégie de sauvegarde/chargement
    Salut,

    Afin d'implémenter une gestion utilisateur multi-rôles, j'ai utilisé le pattern décorateur sur cet ensemble d'objets :

    - ActorAbs (objet abstrait [abstract] )
    - ActorCrt (objet concret [extends ActorAbs] )
    - ActorDecoratorAbs (décorateur abstrait [abstract, extends ActorAbs] )
    - TeacherDecoratorCrt (décorateur concret [extends ActorDecoratorAbs])
    - PupilDecoratorCrt (décorateur concret [extends ActorDecoratorAbs])

    La création d'un utilisateur (Actor), ayant les rôles d'élève mais également d'enseignant, se fait comme suit :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     
    Actor actor;
     
    actor = null;
     
    actor = new ActorCrt();
    actor = actor.decorate(PupilDecoratorCrt.class);
    actor = actor.decorate(TeacherDecoratorCrt.class);
    La sauvegarde d'un utilisateur dans la base fonctionne bien : en utilisant un générateur d'identifiants "hilo", l'enregistrement dans la table 'teacherdecorator' reçoit l'identifiant '1', la table 'pupildecorator' reçoit l'identifiant '2', etc., jusqu'à atteindre l'objet concret non-décoré (ActorCrt).

    L'enregistrement de cet utilisateur renvoit donc l'identifiant '1', que je stocke.

    Par contre, logiquement, un problème survient lors du chargement d'un utilisateur depuis la base.

    Lors du chargement, les rôles attribués à l'utilisateur sont inconnus, la seule chose dont nous disposons est son identifiant dans la base.

    Aussi, je tente de charger l'utilisateur ainsi :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
    Actor actor;
     
    actor = null;
     
    actor = new ActorCrt();
     
    actor.setId(new Long("1"));
    actor.load();
    Fournir l'identifiant à l'utilisateur de base en vue du chargement me semble être la seule solution possible (on ne peut présumer à l'avance de la nature de l'utilisateur), mais çà ne peut pas marcher ainsi, car l'identifiant de l'utilisateur n'est pas référencé dans la table de l'utilisateur de base (bas de la pile), mais dans celle du rôle 'teacherdecorator' (haut de la pile), si l'on reprend l'exemple ci-dessus.
    Est-ce un mauvais choix de programmation ?

    Voilà, je n'ai pas jugé utile de poster tout le code, sachant que le problème est plus conceptuel qu'autre chose.

    Pour le moment, j'envisage les solutions suivantes :

    - utilisation du même identifiant d'enregistrement pour chacun des rôles d'un même acteur ( 'teacherdecorator' (1) --> 'pupildecorator' (1) --> 'actorcrt' (1) )
    Si cette solution est possible, pouvez-vous m'expliquer comment la mettre en oeuvre (quel générateur utiliser, foreign, etc.). J'ai lu que l'on ne peut pas avoir deux fois le même identifiant dans une même session, même pour des enregistrements de tables différentes.

    - retourner l'identifiant de l'objet de base (et non pas celui de l'objet décoré), puis utiliser des associations bidirectionnelles pour remonter à l'objet décoré. Par exemple : pour 'teacher --> pupil --> actor' = '1 --> 2 --> 3', réussir à retourner '3' (au lieu de '1' à l'heure actuelle). Cependant, mes essais de retourner l'identifiant de l'objet de base dans les méthodes 'getId()' de chaque décorateur m'ont menés à l'erreur 'identifier was altered from <id> to <id>'.

    - recherche explicite de l'identifiant dans un ensemble de tables candidates [teacher, pupil, etc.]
    Cette solution est d'ailleurs vouée à l'échec : si une décoration 'teacher --> pupil --> actor' a les identifiants '1 --> 2 --> 3' et qu'une autre décoration successive 'teacher --> pupil --> actor' reçoit donc les identifiants '2 --> 3 --> 4', la recherche de l'identifiant n°2 dans les tables 'teacher' et 'pupil' sera incapable de distinguer à quel table l'objet appartient.

    Si possible, je souhaite éviter les associations bidirectionnelles et le générateur 'foreign', car ils sont sources de code "inutile/dédié Hibernate" dans les classes Java (exemple : si une classe Voiture est composée d'une instance de Roue (voir 4 instances, çà roule mieux ), il est dommage de devoir garder une référence sur la classe Voiture dans une méthode 'getVoiture()' de la classe Roue).

    Que me conseillez-vous ?

    Merci.

  2. #2
    Membre régulier
    Profil pro
    Inscrit en
    Avril 2004
    Messages
    56
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2004
    Messages : 56
    Points : 77
    Points
    77
    Par défaut
    Bon, on dirait que l'utilisation d'association bidirectionnelles est obligatoire ici :

    Pour sauvegarder :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    Actor actor = new TeacherDecorator(new PupilDecorator(new Actor()));
    actor.save();
    Long tempId = actor.getId();
    actor = null;
    Pour charger :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    actor = new Actor(tempId);
    actor.load();
    Par défaut, un décorant connaît son décoré (sauvegarde), mais un décoré ne connaît pas son décorant (chargement) :

    'Actor' étant l'objet de base non-décoré, il ne connaît pas son décorateur de 1er niveau, et le décorateur de 1er niveau ne connaît pas celui de 2nd niveau, etc., d'où la nécessité d'utiliser des associations bidirectionnelles.

    Aussi, lorsqu'un autre sujet du forum, sur le pattern décorateur, parle de ce pattern comme d'une pile (http://www.developpez.net/forums/sho....php?p=2619639), j'en parlerais ici, au niveau de sa persistance, comme d'une liste doublement chaînée.

  3. #3
    Membre régulier
    Profil pro
    Inscrit en
    Avril 2004
    Messages
    56
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2004
    Messages : 56
    Points : 77
    Points
    77
    Par défaut
    Salut,

    Y'a vraiment personne pour me porter conseil svp ?

    Je n'arrive pas à trouver de solution qui fonctionne.

    J'ai tenté d'utiliser le générateur "foreign", mais étant donné que le décorateur est un pattern récursif, cela ne peut pas marcher.

    Lorsque je sauvegarde un acteur décoré en élève, la sauvegarde retourne l'identifiant de l'enregistrement de la table decorateur_eleve.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    DecorateurEleve eleve = new DecorateurEleve(new Actor());
    eleve.save();
    Long tempId = eleve.getId();
    eleve = null;
    Lors du chargement, je dispose de cet 'id' mais ne sais pas d'avance à quelle table l'enregistrement appartient. Par défaut, je ne peux que chercher dans la table de base, acteur, et ne trouve forcément pas l'enregistrement recherché.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    Actor acteur = new Actor(tempId);
    acteur.load();
    Comment gérer ce problème ?

  4. #4
    Membre régulier
    Profil pro
    Inscrit en
    Avril 2004
    Messages
    56
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2004
    Messages : 56
    Points : 77
    Points
    77
    Par défaut
    Pour ne pas perdre trop de temps là-dessus, je me suis décidé pour cette solution plutôt dégueulasse :

    - chaque acteur sauvegardé (qu'il s'agisse d'un enregistrement de teacher_decorator, pupil_decorator, actor, etc.) est relié à une tierce table : 'actorpersister'. Cette table donne un point d'entrée au chargement d'un acteur et permet, à partir d'un identifiant-utilisateur, de remonter au type de l'utilisateur.

    - pour le chargement d'un acteur, le code suivant n'est pas envisageable (si l'acteur à charger est un enseignant, il ne pourra pas être chargé ainsi, car instancié en tant qu'acteur standard, plus restreint, initialement) :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    Actor acteur = new Actor(tempId);
    acteur.load();
    J'utilise donc à contre-coeur une méthode statique de ce type :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    Actor acteur = Actor.load(tempId);
    Seule l'utilisation d'une méthode statique semble permettre de charger n'importe quel type d'acteur.

    Voilà, pas de flag "Résolu" : je laisse le sujet ouvert pour discussion sur le thème "pattern décorateur et persistance", des fois qu'un développeur intéressé passe par là et vienne apporter de l'eau au moulin, un jour peut-être..

Discussions similaires

  1. Stratégie de sauvegarde
    Par psyco2604 dans le forum MS SQL Server
    Réponses: 3
    Dernier message: 06/06/2007, 13h56
  2. [HIBERNATE] pattern Open Session in View
    Par _beber85 dans le forum Hibernate
    Réponses: 1
    Dernier message: 10/05/2006, 10h04
  3. [Plugin][Hibernate] Patterns DAO avec hybernate
    Par BarbapapaDK dans le forum Eclipse Java
    Réponses: 1
    Dernier message: 13/03/2006, 09h53
  4. [TObjectList]Sauvegarde/Chargement
    Par ghost942 dans le forum Langage
    Réponses: 4
    Dernier message: 22/02/2006, 07h59
  5. Sauvegarde / Chargement d'un tableau d'objets
    Par Naruto dans le forum Langage
    Réponses: 3
    Dernier message: 18/05/2004, 14h34

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