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

Spring Web Java Discussion :

Modèles de classes en Java et TypeScript


Sujet :

Spring Web Java

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre très actif
    Profil pro
    Inscrit en
    Mai 2010
    Messages
    132
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2010
    Messages : 132
    Par défaut Modèles de classes en Java et TypeScript
    Bonjour,

    Dans ma montée en compétences, j'ai donc créé une petite appli toute simple que se soit côté backend (spring boot) et frontend (angular).

    J'ai créé 2 classes en Java : Client et Commande avec une relation OneToMany pour Client et ManyToOne pour Commande.

    Donc, dans Client.java j'ai :
    @OneToMany
    private List<Commande> commandes;
    Et dans Commande.java j'ai :
    @ManyToOne
    private Client client;
    Est-ce que je dois créer exactement le même modèle sous Angular (TS) ? Un tableau de commande dans client.ts et un object Client dans commande.ts ? Comment retranscrire ces relations dans Angular ?

    Merci d'avance

  2. #2
    Membre très actif

    Profil pro
    Inscrit en
    Janvier 2009
    Messages
    483
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2009
    Messages : 483
    Billets dans le blog
    5
    Par défaut
    La réponse est non, mais les arguments durs à exposer.

    Pour commencer, on va commencer par la couche basse.

    La couche basse, que l'on va appeler "entity" est manipulée par les DAO ( https://www.baeldung.com/java-dao-pattern ).

    C'est en général, JPA/Hibernate qui est utilisé, mais on peut utiliser autre chose qu'une BDD Relationnelle (MongoDB,...), voir un autre framework (Spring JDBC...).

    Partons des tables. Tu as une table commande qui a une clé étrangère sur la table client.

    Ton Mapping est donc correct, mais il est incomplet.

    Cette partie étant critique, je recommande d'être psychorigide et vieux con, comme:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
     
    @Entity
    @Table(name="COMMANDE")
    public class Commande{
     //ID et Attribut
     
     @ManyToOne(fetch = FetchType.LAZY)
     @JoinColumn(name="CLIENT_ID", nullable=false)
     private Client client;
     
     //Getter Setter
    }
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     
    @Entity
    @Table(name="CLIENT")
    public class Client{
     //ID Attribut
     
     @ManyToOne(fetch = FetchType.LAZY,mappedBy = "client")
     
     //Getter Setter
    }
    Là, on a mappé au mieux la BDD. A noté que j'ai ajouté la notion de LAZY/EAGER qui est fondamentale.
    EAGER: Quand tu sélectionne la classe, Hibernate va aussi récupérer la classe lié (ce qui a partir d'un moment, revient à faire des requêtes en plus).

    LAZY: On signale le lien mais Hibernate ne va pas chercher les données.

    Couche suivante: DTO et Service.
    Le lien est sympa, mais au fond, pour le service REST Spring, on n'a pas forcement besoin de toutes les informations.
    Admettons que l'on cherche les commandes d'un client connu, là, on va vraiment couper, car en gros, la requête JPQL sera
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    SELECT commande FROM Commande commande WHERE commande.client.id = :idClient
    Du coup, je n'ai pas besoin de passer à l'extérieur le client lorsque je lui passe la liste des commande.

    Mieux, je ne passe peut-être que quelques données de la commande (numéro, date...) et pas le détail.
    Donc la DTO devient:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     
    public class CommandeDTO{
     private String numeroComande;
     private String date;//Un string ici, sans doute une Date en BDD
     //Autre truc que je veux communiquer à l'extérieur
     
     //Le client, j'en ai rien à faire ici
     
     //Des Getter et des Setteur 
    }
    Cette façon peut aussi te sauver la vie car si tu construit des JSON, tu peux avoir des problème (concrètement des boucles de l'entité).

    Ici, tu as les classes mappant la BDD et celles qui serves à communiquer vers l'extérieur. A toi de mapper dans un sens ou l'autre.

  3. #3
    Membre très actif

    Profil pro
    Inscrit en
    Janvier 2009
    Messages
    483
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2009
    Messages : 483
    Billets dans le blog
    5
    Par défaut
    De fait, j'ai oublié de dire que dans Angular, en général, c'est ton modèle DTO, et non Entity. Évidement, tu peux couper également de la DTO vers le modèle angular.

  4. #4
    Membre très actif
    Profil pro
    Inscrit en
    Mai 2010
    Messages
    132
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2010
    Messages : 132
    Par défaut
    Citation Envoyé par PhilippeGibault Voir le message
    De fait, j'ai oublié de dire que dans Angular, en général, c'est ton modèle DTO, et non Entity. Évidement, tu peux couper également de la DTO vers le modèle angular.
    Pour une entité, j'ai créé un Repo qui étend JPARepository, un service et un contrôleur.

    Mon soucis c'était que lorsque je créais un client, pas de soucis.
    Dès que j'ajoutais une commande, c'était la catastrophe... ça plantait et quand j'allais voir l'url de l'api, ça avait inscrit plusieurs fois la commande et plusieurs fois dans le tableau de client aussi..la donnée était à chaque fois imbriqué dans le tableau... à l'infini on dirait jusqu'à plantage

    Je ne sais pas pour quelle raison ça fonctionne mais j'ai ajouté l'annotation @JsonIgnore à la relation OneToMany et ça a l'air de fonctionner mais je ne sais pas si ça l'enregistre en base... Je ne sais pas comment vérifier que ma relation existe. J'utilise MySQL via le PHPMyAdmin sous Ubuntu

    @JsonIgnore
    @OneToMany(targetEntity = Commande.class, mappedBy = "client")
    private List<Commande> commandes;
    De plus, je ne vois pas comment récupérer les commandes d'un client si je met cette annotation @JsonIgnore

  5. #5
    Membre très actif

    Profil pro
    Inscrit en
    Janvier 2009
    Messages
    483
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2009
    Messages : 483
    Billets dans le blog
    5
    Par défaut
    Non.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     
    public class ClientDTO{
     
     private List<CommandeDTO> commandes;
     
     //ect 
    }
    La DTO étant ce qui va être transféré.

    Un détail:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    @OneToMany(targetEntity = Commande.class, mappedBy = "client")
    private Set<Commande> commandes;
    Le Set est préféré à la List, car chaque commande est sensé être unique.

    Après, à toi de faire le mapping entre les DTO et les Entités.

  6. #6
    Membre très actif

    Profil pro
    Inscrit en
    Janvier 2009
    Messages
    483
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2009
    Messages : 483
    Billets dans le blog
    5
    Par défaut
    Je peux te donner le lien de mon projet perso pour l'exemple:
    https://bitbucket.org/philippegibaul...r40k/src/main/

    Pour commencer, @JsonIgnore n'est pas la solution mais le problème. C'est même une mauvaise pratique.

    En gros, tu as deux classes, Commande et Client qui sont liées et tu transforme en JSON des données qui sont dans des POJO.
    Tu cherches à avoir la commande et son client.

    L'ensemble prend la commande, JSON, pas de problème.

    Puis, il prend le client lié à la commande, JSON, pas de problème.

    Puis il prend les commandes (toutes!!!!!!!) pour JSON.

    Puis il prend les clients de chaque commande (qui en plus est le même) et JSON.

    Puis pour chaque client (qui est le même) il prend encore les commandes puis re-JSON.

    Bref -> Boucle infini.

    Le @JsonIgnore sert à justement stopper ce processus infernal!

    Mais la bonne pratique est de différentier ce que l'on transfert vers l'extérieur (la DTO pour Data Transfert Object) de l'entité.

    En fait, tu découpe en couche. et en rôles. Mapper la BDD n'a rien à voir avec transférer les informations vers l'extérieur. C'est deux rôles différents.

    La couche la plus basse
    Les POJO sont les entités. Là, tu mappe avec la BDD via JPA (et ses annotations diverses et variées).

    Ce qui manipule les Entités sont les DAO. Ce sont en général des CRUD (https://fr.wikipedia.org/wiki/CRUD ).
    C'est dans les DAO que tu écris les requête en BDD.

    Couche service
    Ici, tu va injecter des DAO. Et des classe de mapping pour passer de la DTO vers l'entité ou inversement.
    Tu peux implémenté des règles métiers ici, même si aujourd'hui, on a changé d'approche (Architecture hexagonale).
    Le service retourne les DTO.

    Couche Rest
    Tu injecte les services ici.

  7. #7
    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 PhilippeGibault Voir le message

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     
    @Entity
    @Table(name="CLIENT")
    public class Client{
     //ID Attribut
     
     @ManyToOne(fetch = FetchType.LAZY,mappedBy = "client")
     
     //Getter Setter
    }
    "Petite" erreur, c'est une annotation OneToMany de ce côté.
    N'oubliez pas de consulter les FAQ Java et les cours et tutoriels Java

  8. #8
    Membre très actif
    Profil pro
    Inscrit en
    Mai 2010
    Messages
    132
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2010
    Messages : 132
    Par défaut
    Citation Envoyé par OButterlin Voir le message
    "Petite" erreur, c'est une annotation OneToMany de ce côté.
    Exact, c'est ce que j'ai mis @OneToMany

  9. #9
    Membre très actif
    Profil pro
    Inscrit en
    Mai 2010
    Messages
    132
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2010
    Messages : 132
    Par défaut
    Citation Envoyé par PhilippeGibault Voir le message
    La réponse est non, mais les arguments durs à exposer.

    Pour commencer, on va commencer par la couche basse.

    La couche basse, que l'on va appeler "entity" est manipulée par les DAO ( https://www.baeldung.com/java-dao-pattern ).

    C'est en général, JPA/Hibernate qui est utilisé, mais on peut utiliser autre chose qu'une BDD Relationnelle (MongoDB,...), voir un autre framework (Spring JDBC...).

    Partons des tables. Tu as une table commande qui a une clé étrangère sur la table client.

    Ton Mapping est donc correct, mais il est incomplet.

    Cette partie étant critique, je recommande d'être psychorigide et vieux con, comme:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
     
    @Entity
    @Table(name="COMMANDE")
    public class Commande{
     //ID et Attribut
     
     @ManyToOne(fetch = FetchType.LAZY)
     @JoinColumn(name="CLIENT_ID", nullable=false)
     private Client client;
     
     //Getter Setter
    }
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     
    @Entity
    @Table(name="CLIENT")
    public class Client{
     //ID Attribut
     
     @ManyToOne(fetch = FetchType.LAZY,mappedBy = "client")
     
     //Getter Setter
    }
    Là, on a mappé au mieux la BDD. A noté que j'ai ajouté la notion de LAZY/EAGER qui est fondamentale.
    EAGER: Quand tu sélectionne la classe, Hibernate va aussi récupérer la classe lié (ce qui a partir d'un moment, revient à faire des requêtes en plus).

    LAZY: On signale le lien mais Hibernate ne va pas chercher les données.

    Couche suivante: DTO et Service.
    Le lien est sympa, mais au fond, pour le service REST Spring, on n'a pas forcement besoin de toutes les informations.
    Admettons que l'on cherche les commandes d'un client connu, là, on va vraiment couper, car en gros, la requête JPQL sera
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    SELECT commande FROM Commande commande WHERE commande.client.id = :idClient
    Du coup, je n'ai pas besoin de passer à l'extérieur le client lorsque je lui passe la liste des commande.

    Mieux, je ne passe peut-être que quelques données de la commande (numéro, date...) et pas le détail.
    Donc la DTO devient:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     
    public class CommandeDTO{
     private String numeroComande;
     private String date;//Un string ici, sans doute une Date en BDD
     //Autre truc que je veux communiquer à l'extérieur
     
     //Le client, j'en ai rien à faire ici
     
     //Des Getter et des Setteur 
    }
    Cette façon peut aussi te sauver la vie car si tu construit des JSON, tu peux avoir des problème (concrètement des boucles de l'entité).

    Ici, tu as les classes mappant la BDD et celles qui serves à communiquer vers l'extérieur. A toi de mapper dans un sens ou l'autre.
    Si je comprends bien, tu ne passes pas par le repo, service, controleur comme j'ai fait ?

    La requete JPQL, je l'écrit où ?

Discussions similaires

  1. Créer un modèle uml diag de classe sous java?
    Par jalil85 dans le forum UML
    Réponses: 2
    Dernier message: 04/11/2008, 00h04
  2. [Reflection]parser une classe de java.
    Par burkan21 dans le forum API standards et tierces
    Réponses: 9
    Dernier message: 02/12/2005, 21h05
  3. Réponses: 7
    Dernier message: 21/06/2005, 17h04
  4. Réponses: 5
    Dernier message: 15/02/2005, 10h32
  5. [PL/SQL]Appel d'une classe/méthode java
    Par marsup54 dans le forum SQL
    Réponses: 4
    Dernier message: 30/06/2004, 16h44

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