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 :

Problème de mapping de double clef primaires


Sujet :

Hibernate Java

  1. #1
    Membre émérite

    Homme Profil pro
    Développeur informatique
    Inscrit en
    Octobre 2013
    Messages
    1 065
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Conseil

    Informations forums :
    Inscription : Octobre 2013
    Messages : 1 065
    Points : 2 567
    Points
    2 567
    Par défaut Problème de mapping de double clef primaires
    Bonjour,

    J'ai un petit problème pour mapper mes clef primaire sur une arborescence .

    J'ai une classe mère abstraite Ecriture et deux classes fille EcritureDEBrouillard et Ecriture Validée.

    Dans la classe EcritureDeBrouillard la clef primaire est NumeroDePreEnregistrement

    Et dans EcritureValidee la clef primaire est NumeroEnregistrement
    J'ai également un champs NuméroPréEnregistrement, car je veux en garder la trace.
    Si mon utilisateur n'a pas noté le numéro d'enregistrement il peut toujours utiliser le numero de préenregistrement

    Quand je valide je détruit mon objet Ecriture de brouillard après l'avoir copié dans une EcritureValidee et avoir générer un numéro d'enregistrement, qui à la priorité pour la recherche.

    Pour l'instant ma solution me semble un peu bencale.
    J'utilise un mapping une table par class, car j'ai peur qu'avec un apping "single table" ça soit ambiguë pour la colonne numeroPreEnregistrement

    Dans EcritureDeBrouillard j'ai un champs clef primaire NumeroPreEnregistrement

    Et dans EcriturValidee j'ai un champs numeroEnregistrement commme clef primaire
    et à nouveau un autre champs numeroPreEnregistrement, en normal cette fois, qui est la copie de l'autre clef primaire de l'autre classe.

    J'aimerai bien remonté ma propriété numéroPréEnregistrement dans la classe mère, tout en sachant que c'est une clef primaire seulement pour la classe fille EcritureDEBrouillard
    Pour la classe fille EcritureValidee c'est une clef secondaire,
    J'ai peur que ce soit un paradox pour Hibernate.

    Est-ce que je peux l'annoter "unique not null", comme en SQL pour l'intégrité ?
    J'aimerai bien avoir aussi un index pour optimiser la recherche pour cette clef secondaire.

    Je ne veux pas de clef concaténée.
    Et on a pas droit d'utiliser deux fois @Id.

    Comment je peux améliorer ma solution ?

    Merci de m'avoir lu ;D
    Consultez mes articles sur l'accessibilité numérique :

    Comment rendre son application SWING accessible aux non voyants
    Créer des applications web accessibles à tous

    YES WE CAN BLANCHE !!!

    Rappelez-vous que Google est le plus grand aveugle d'Internet...
    Plus c'est accessible pour nous, plus c'est accessible pour lui,
    et meilleur sera votre score de référencement !

  2. #2
    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
    J'aurais tendance à penser que tu te compliques la vie pour une notion de clé primaire.

    Pourquoi changer la clé primaire de ton enregistrement pour une notion de validation, tu pourrais garder la même, ça n'empêche pas d'avoir un autre champ pour une clé d'accès.
    C'est un peu la même logique pour une facture pro forma, quand tu la valides il suffit de générer le numéro de facture (qui suit ses règles) et l'ajouter dans la colonne cible.
    Pour tes recherches, tu peux y accéder soit par la clé primaire (qui serait celle de la pro forma dans cet exemple) soit par le numéro de facture (pour celles qui en ont).

    Bref, tu peux imaginer une table qui contient les données communes (liée à ta classe abstraite) et 2 tables pour tes données spécifiques (si besoin) :
    - 1 pour EcritureDEBrouillard
    - 1 pour EcritureValidee
    Et jouer sur le système de @DiscriminatorColumn / @DiscriminatorValue pour le mapping des entity.


    Ce système n'a d'intérêt que si les données peuvent être modifiées entre les 2 étapes, sinon, tu peux tout mettre dans une seule table.
    N'oubliez pas de consulter les FAQ Java et les cours et tutoriels Java

  3. #3
    Membre émérite

    Homme Profil pro
    Développeur informatique
    Inscrit en
    Octobre 2013
    Messages
    1 065
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Conseil

    Informations forums :
    Inscription : Octobre 2013
    Messages : 1 065
    Points : 2 567
    Points
    2 567
    Par défaut
    Oui tu as raison je me complique la vie.
    C'est juste que la propriété numéroEnregistrement est plus importante.
    C'est pour ça que je voulais que se soit elle la clef primaire, mais ça fausse tout.

    Finalement je remonte la propriété numeroPreEnregistrement dans la classe mère abstraite, et en fait une clef primaire commune aux deux classe filles.
    Je prend le mapping une table uniique pour toutes les classes.
    Je pense qu'il sera plus rapide, j'ai des requêtes qui mélange les deux objets, et je n'ai qu'une colonne de différence.
    A la base si un objet EcritureDeBrouillard n'est pas validé, il est supprimé à moyen terme.
    Donc ça ne consomme pas trop de mémoire, et surtout ça ne doit pas auguementer.

    Mais pour ma propriété Numero enregistrement je peux annoter ainsi ?
    Pour retrouver le comportement de la clef primaire auto incrémenter
    @Column(nullable = false)
    @Column(unique = true)
    @GeneratedValue(strategy = GenerationType.AUTO)
    protected int numeroEnregistrement = 0;

    Je ne ssais pas s'y j'ai droit à l'"auto increment"
    Pour avoir un premier nivveau de sécurité il faut que je m'assure que les numéro d'enregistrement se suivent, sinon ça veut dire qu'il y à eut manipulation

    Et comme ça va être un outil de recherche, comment aider à l'optimisation ?
    Peut on Demander à Hibernate de créer un index sur cette colonne?

    Merci de ton aide
    Consultez mes articles sur l'accessibilité numérique :

    Comment rendre son application SWING accessible aux non voyants
    Créer des applications web accessibles à tous

    YES WE CAN BLANCHE !!!

    Rappelez-vous que Google est le plus grand aveugle d'Internet...
    Plus c'est accessible pour nous, plus c'est accessible pour lui,
    et meilleur sera votre score de référencement !

  4. #4
    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
    La colonne numeroEnregistrement est forcément nullable puisqu'au pré-enregistrement elle ne peut avoir de valeur.
    Elle ne peut pas non plus utiliser une séquence de manière "automatique" puisque ce n'est qu'à un moment que tu en as besoin dans le cycle de vie de ton enregistrement.
    Tu peux par contre utiliser une requête max(numeroEnregistrement) pour calculer le prochain numéro au moment où l'enregistrement passera de "pré-enregistrement" à "enregistrement".
    Pour garantir l'unicité, le plus "portable" serait de passer par un trigger qui fera une requête pour tester si la valeur de "numeroEnregistrement" n'a pas déjà été affectée à un autre enregistrement (en se basant sur un test de la clé primaire).

    Pour l'optimisation, un simple index sur ta colonne "numeroEnregistrement" devrait suffire...
    N'oubliez pas de consulter les FAQ Java et les cours et tutoriels Java

  5. #5
    Membre émérite

    Homme Profil pro
    Développeur informatique
    Inscrit en
    Octobre 2013
    Messages
    1 065
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Conseil

    Informations forums :
    Inscription : Octobre 2013
    Messages : 1 065
    Points : 2 567
    Points
    2 567
    Par défaut
    Désolé pour le retard j'ai cogité.
    J'ai plusieurs problèmes.

    Je dois travailler avec un petit moteur comme HSqlDb, sinon MySql pour des besoin plus poussés.
    Je ne crois pas que HsqlDb gère les triggers.
    Je cherche à rester indépendant du SGBD

    A moins que Hibernate gère les trigger au dessus de la base.
    Je n'en ai pas utiliser régulièrement
    Je n'ai pas trouvé de réponse claire à ce sujet.
    Et de toute façon je passais plutôt par une transaction, voire plus bas.
    Car je pense que c'est plus sûr.

    Me second problème est que pour créer une "EcritureValidee", je supprimais l'"EcriturePreEnregistree".
    Ma première solution a été d'utiliser une clef de substitution déclarée sur la classe mère en "auto increment", et de gérer les deux numéro de préenreggistrement et numéro de validation moi même.
    Cette clef de substitution n'avait pas beaucoup de sens et ne pouvait pas être un outil de sécurité.
    Je cherche à me prémunir des insertion à posteriori, un enregistement intercallé en particulier

    En fait je supprimais l'écriture préenregistrée et j'en créais une validée avec les éléments de l'autre.
    Là si je garde le numéro de préenregistrement en "auto_increment".
    Il va s'incrémenter à la création de l'écriture validée .
    Je n'avais pas ce problème avec la clef de substitution.

    L'idéal serait de pouvoir manipuler la colonne discriminante et de changer la classe de mon objet d''"EcriturePreEnregistree" à "EcritureValidee".
    Je n'y ai jamais pensé avant.

    En pseudo code je faisais pour la validation

    Validation ecriture
    monNumero = select max(numeroEnreggistrement)+1 from EcritureValidee

    //copie les éléments de l'écriture préenregistrér dans une écriture validée.
    EcritureValidee = ecriturePreEnregistre.valider();
    ecritureValidee.setNumeroEnregistrement(monNumero);

    débuter une transaction
    persister(l'écriture) validée
    supprimer l'écriturePreEnregistrée

    Si
    select count(id) from ecritureValidee where numero = mon numero
    > 1
    //echec
    annuler la transaction
    sinon
    Valider la transaction


    En cas d'échec il faut analyser le pourquoi, pour éviter de redemander en vain une validation avec un nouveau numéro.
    Là je ne suis pas dans un contexte concurrentiel.
    Donc ça n'doit pas arriver.
    Consultez mes articles sur l'accessibilité numérique :

    Comment rendre son application SWING accessible aux non voyants
    Créer des applications web accessibles à tous

    YES WE CAN BLANCHE !!!

    Rappelez-vous que Google est le plus grand aveugle d'Internet...
    Plus c'est accessible pour nous, plus c'est accessible pour lui,
    et meilleur sera votre score de référencement !

Discussions similaires

  1. Problème contrainte clef primaire
    Par saiffadi dans le forum Langage SQL
    Réponses: 2
    Dernier message: 22/02/2012, 19h51
  2. Problème avec une clef primaire
    Par marcbo dans le forum VBA Access
    Réponses: 14
    Dernier message: 23/03/2011, 11h16
  3. Problème de clef primaire
    Par bigsister dans le forum Requêtes
    Réponses: 1
    Dernier message: 15/01/2008, 18h46
  4. Problème recup clef Primaire doublons
    Par nathieb dans le forum SQL
    Réponses: 4
    Dernier message: 13/09/2007, 15h55
  5. Réponses: 4
    Dernier message: 08/03/2006, 13h22

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