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

Servlets/JSP Java Discussion :

Problème d'accès aux données


Sujet :

Servlets/JSP Java

  1. #1
    Membre averti
    Profil pro
    Inscrit en
    Juillet 2009
    Messages
    58
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juillet 2009
    Messages : 58
    Par défaut Problème d'accès aux données
    Bonjour à tous,

    Je travail sur mon premier projet Web en java (JSP/Servlet EJB3 netbeans 7) et j'ai un petit problème que je n'arrive pas a résoudre.

    Je vous explique donc au niveau de ma BDD j'ai 3 tables:
    -Client
    -Account (type de compte bancaire et un clé étrangère vers client)
    -Historique (date d'une oppération, montant de l'oppération, clé étrangère vers account)

    Ensuite j'ai créé les classes d'entités (clique droit Entity classes from database).

    Ce qui fonctionne pratiquement pour tout mon projet sauf lorsqu'il y a des jointures. Et je ne sais absolument pas comment procéder.

    J'ai commencé par rajouter l'attribut "Total" à l'entity class Account avec le tag "@transient". Je ne sais pas si c'est bon mais sinon il m’envoie bouler car Total n'est pas un champ de la table account.

    Bref j'ai essayé de modifier la requête en rajoutant la jointure avec la table opération mais je ne comprend pas comment ça fonctionne donc je n'y arrive pas. De base il retourne un objet de type Account, moi c'est ce que je veux sauf que je veux qu'en plus dans cette objet se trouve le total qui provient de la somme des montants de l'historique associé au compte.

    Merci à vous de m'éclairer sur ce sujet.

  2. #2
    Membre confirmé
    Homme Profil pro
    Développeur Java
    Inscrit en
    Mai 2010
    Messages
    104
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Calvados (Basse Normandie)

    Informations professionnelles :
    Activité : Développeur Java
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Mai 2010
    Messages : 104
    Par défaut
    Collègue Supinfo bonjour,

    Bien que ta question ne soit pas clairement formulé, je vais essayer de te mettre sur le bon chemin. Et puis, je travaille dessus en ce moment même donc je vois bien de quoi tu parles. (Pas sûr qu'un internaute hors-supinfo comprennent! )

    Avant de commencer, je suppose qu'un objet "historique" correspond à 1 opération sur le compte, d'ailleurs tu devrais lui donner un nom plus explicite comme "AccountOperation". C'est ce que j'utiliserai par la suite.

    En ce qui concerne les jointures entre tes tables, je suppose que tu as quelque chose dans le genre :

    1 client a plusieurs account
    1 account a plusieurs AccountOperation


    Ce qui se traduirait en annotations JPA :
    Client entity :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    @OneToMany
    List<Account> accounts;
    Account entity :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    @OneToMany
    List<AccountOperation> historique;
    JPA se charge de faire les jointures tout seul. Lorsque ta base est générée à partir de tes entity, par défaut tu devrais avoir une table qui permet de joindre tes tables. Pour accéder à la liste de comptes d'un client, un simple client.getAccounts() (getter) retrouve cette liste. De même pour account.getHistorique(); JPA fait le lien pour toi et gère le JOIN!
    Pense à initialiser ces attributs avec une liste vide avant d'appeler ton EntityManager (j'espère que c'est clair pour toi ).
    (Attention avec Client, il me semble qu'un client doit obligatoirement avoir au moins 1 compte)

    Voilà pour les jointures entre tables, qui en fait sont gérées toutes seules par JPA.

    Pour la deuxième question, je comprend que tu souhaites faire la somme des 'amounts' de chaque AccountOperation pour un Account donné pour déterminer le solde du compte.

    L'attribut annoté "@Transient" sera déduit depuis d'autres informations mais ne sera pas persisté en base. Il est donc normal que la table Account ne possède pas de champs 'Total' (en bdd), et lorsque tu récupères un objet Account depuis ta base, l'attribut est vide. Il faut penser à appeler un méthode dédiée (cf ci-dessous) à chaque fois que tu récupères un Account.
    Tu peux implémenter cette méthode dans l'entity Account directment :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    @Entity
        public class Account {
     
            //Attributs
            [...]
            @Transient
            private Float total;
     
            //GETTERS & SETTERS
            [...]
            public Float getTotal(){
                return total;
            }
            public void setTotal(Float tot) {
                this.total = tot;
            }
     
            // THE methode
            public void deduceTotal() {
                //tu récupères ta liste d'opération attaché au compte (this).
                List<AccountOperation> historique = this.getAccountOperations();
                //si aucune opération, alors total = 0 (important!)
                Float total = 0;
                //tu itères sur ta liste et actualise total à chaque passge
                for (AccountOperation op : historique) {
                    total = total + op.amount;
                }
                this.setTotal(total);
            }
        }
    Et l'appeler ensuite après avoir récupérer un account depuis ta bdd:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    [...]
    Account acc = accountDao.findAccountById(...);
    acc.deduceTotal();
    System.out.println(acc.getTotal()); //Affiche le total
    Voilà pour récupérer le total utilisant le @Transient.

    Je me permet une remarque. Même si cette technique tient la route et devrait fonctionner, c'est tout de même gourmand en ressource, pour simplement gagner une colone de Float en Base de donnée.

    Il vaut mieux qu'un compte possède un champs persistant, non-transcient, "total" (au passage, les variables commencent par une minuscule en Java) qui soit actualisé à chaque opération, plutôt qu'un attribut transcient qui t'oblige à calculer le montant à chaque fois que tu récupères un compte.

    Imagine si un compte à 10000 opérations - c'est un vieux compte toujours très actif - c'est gourmand en processeur : il doit itérer 10000fois sur sa liste d'opération pour simplement retrouver le total.

    J'espère que cette longue explication te permet d'y voir un peu plus clair!
    Bon courage pour terminer!!

  3. #3
    Membre averti
    Profil pro
    Inscrit en
    Juillet 2009
    Messages
    58
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juillet 2009
    Messages : 58
    Par défaut
    Bien vue l'ami !

    Je comprend ce que tu veux dire j'ai rédigé trop vite (je sature à force).
    j'ai fini mon projet finalement.

    Ce que je cherchais comme solution c'était de récupérer directement (comme on l'aurais fait avec un simple join) le SUM des montants des historiqueAccount.
    A mon avis c'est possible mais je n'ai pas trouvé donc j'ai procédé de la sorte:

    Un foreach sur la collection Account
    GetID()
    Je récupère le total des historique qui répondent à la clause FkAccount= ID
    SetTotal();

    Du coup comme un user n'a que quelques compte et pas des milliers ça ne devrais pas trop consommer en mémoire. Je préfère avoir une DAL pas correcte qu'une BDD mal foutue.

    En tout cas merci à toi pour ta réponse cela m'a aidé dans ma réflexion

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

    Informations forums :
    Inscription : Novembre 2006
    Messages : 7 313
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par Doudoupe Voir le message
    Il vaut mieux qu'un compte possède un champs persistant, non-transcient, "total" (au passage, les variables commencent par une minuscule en Java) qui soit actualisé à chaque opération, plutôt qu'un attribut transcient qui t'oblige à calculer le montant à chaque fois que tu récupères un compte.
    Si je peux me permettre, il serait préférable d'utiliser un trigger sur la base de données pour mettre à jour ce champ calculé, plus performant et surtout plus fiable qu'une fonction appelée par l'application...

    Une autre remarque concerne l'explication d'une table pour matérialiser les jonctions.
    Dans la mesure où ici tout est hiérarchique (encore que pour la relation client/compte ce serait discutable), une simple référence (foreign key) de Client dans Account et une autre dans AccountOperation sur Account suffira.
    N'oubliez pas de consulter les FAQ Java et les cours et tutoriels Java

  5. #5
    Membre confirmé
    Homme Profil pro
    Développeur Java
    Inscrit en
    Mai 2010
    Messages
    104
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Calvados (Basse Normandie)

    Informations professionnelles :
    Activité : Développeur Java
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Mai 2010
    Messages : 104
    Par défaut
    Citation Envoyé par OButterlin Voir le message
    Dans la mesure où ici tout est hiérarchique (encore que pour la relation client/compte ce serait discutable), une simple référence (foreign key) de Client dans Account et une autre dans AccountOperation sur Account suffira.
    Effectivement! Il me semblait avoir mis un "par défaut" concernant la génération de la JoinTable. On peut modifier ce comportement avec l'annotation suivante :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    @Entity
    public class Client {
     
        //attributs de Client
        [...]
     
        @JoinColumn(name = "client_fk")
        private List<Account> accounts;
     
        // Constructors, getters, setters
        [...]
    }
    Ce qui aura pour effet de créer une simple colonne "client_fk" dans Account (plus de tablede jointure).

    @OButterlin:
    2 questions qui tu as soulevé dans mon esprit...
    * Pourquoi ce comportement serait-il discutable pour la relation client/compte ?
    * Peux-tu m'expliquer plus clairement ton idée de trigger sur la base de données ?

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

    Informations forums :
    Inscription : Novembre 2006
    Messages : 7 313
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par Doudoupe Voir le message
    @OButterlin:
    2 questions qui tu as soulevé dans mon esprit...
    * Pourquoi ce comportement serait-il discutable pour la relation client/compte ?
    * Peux-tu m'expliquer plus clairement ton idée de trigger sur la base de données ?
    on pourrait imaginer qu'un compte soit partagé entre 2 clients (comme dans le cas d'un compte commun)

    pour les trigger, ils se placeraient sur AccountOperation, il faudrait ajouter un trigger sur l'évènement delete, insert et update (dans le cas d'une modification du montant)
    N'oubliez pas de consulter les FAQ Java et les cours et tutoriels Java

  7. #7
    Membre confirmé
    Homme Profil pro
    Développeur Java
    Inscrit en
    Mai 2010
    Messages
    104
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Calvados (Basse Normandie)

    Informations professionnelles :
    Activité : Développeur Java
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Mai 2010
    Messages : 104
    Par défaut
    Citation Envoyé par OButterlin Voir le message
    Pour les trigger, ils se placeraient sur AccountOperation, il faudrait ajouter un trigger sur l'évènement delete, insert et update (dans le cas d'une modification du montant)
    Merci pour l'astuce! Je vois le principe mais je n'en ai jamais implémenté. Donc je ne vois pas trop comment c'est fait.
    Si tu as le temps, tu aurais un exemple "toucon" à me montrer? Ou peut-être un lien ?

    (Bien vu pour le compte commun! Dans notre sujet, un compte n'appartient qu'à un seul customer, du coup je n'avais pas réfléchi plus loin. )

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

    Informations forums :
    Inscription : Novembre 2006
    Messages : 7 313
    Billets dans le blog
    1
    Par défaut
    La manière de placer un trigger sur une table dépend de la base de données cible, même si par des ordres sql, on couvre la majorité des bases du moment.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    CREATE TRIGGER trigger_name trigger_time trigger_event     ON tbl_name FOR EACH ROW trigger_stmt
    Mieux vaut chercher sur le net des exemples qui correspondent à ta base.
    Pour MySQL, tu peux regarder ceci.

    Le principe d'un trigger est qu'on défini le type d'opération sur un enregistrement (insert/update/delete), le moment du déclenchement (before/after), et on lui rattache du code.
    Le moteur du SGBDR s'occupera tout seul de l'appel.
    Du coup, qu'un modification intervienne depuis une application ou depuis une interface sql (lignes de commandes), on ne peut contourner le trigger...
    N'oubliez pas de consulter les FAQ Java et les cours et tutoriels Java

Discussions similaires

  1. [MVC] Problème d'accés aux données d'un formulaire
    Par reeda dans le forum Spring Web
    Réponses: 1
    Dernier message: 19/01/2009, 15h05
  2. Problème d'acces aux données d'une liste Chainée
    Par Le Payton dans le forum Langage
    Réponses: 4
    Dernier message: 27/08/2007, 11h00
  3. Problème d'accès aux données
    Par phinks94 dans le forum VBA Access
    Réponses: 2
    Dernier message: 22/06/2007, 11h40
  4. [MVC][SQLServer 2005 trial] problème d'accès aux données
    Par olivier57b dans le forum Servlets/JSP
    Réponses: 5
    Dernier message: 01/02/2007, 11h23
  5. problème d'accès aux données sur serveur par poste client
    Par rahan_dave dans le forum Requêtes
    Réponses: 1
    Dernier message: 25/02/2006, 09h13

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