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 Boot Java Discussion :

comment enregistrer correctement une donnée qui possède @joincolumn


Sujet :

Spring Boot Java

  1. #1
    Membre confirmé

    Profil pro
    Inscrit en
    Août 2008
    Messages
    1 191
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2008
    Messages : 1 191
    Points : 595
    Points
    595
    Par défaut comment enregistrer correctement une donnée qui possède @joincolumn
    Bonjour,

    j'ai une entité matière auquel j'ai appliquer une relation avec une autre entité sommaire:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
     
    public class Matiere implements Serializable{
        @Id @GeneratedValue(strategy = GenerationType.IDENTITY) 
        private Long id;
        private String nameMatiere;
        private String route;
        @ManyToOne
        @JoinColumn
        //une matière appartient à un sommaire
        private Sommaire sommaire;
    }
    je tente de faire une requête post pour enregistrer d'une matière , voici ce que j'envoie avec l'outil advance REST

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    //l'url http://localhost:8181/matieres
    {"nameMatiere": "devopplus", "route": "devopplus", "sommaire_id":"1"}
    le problème c'est que je n'arrive pas à insérer correctement le champs "sommaire_id".
    la donnée sommaire_id, me donne NULL alors que je devais avoir un 1:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
     
    | id | name_matiere | route     | sommaire_id |
    +----+--------------+-----------+-------------+
    |  1 | reseaux      | reseaux   |           1 |
    |  2 | linux        | linux     |           1 |
    |  3 | dao          | dao       |           2 |
    |  4 | entities     | entity    |           2 |
    |  5 | NULL         | devopplus |        NULL |
    |  6 | NULL         | devopplus |        NULL |
    |  7 | devopplus    | devopplus |        NULL |
    |  8 | devopplus    | devopplus |        NULL |
    |  9 | devopplus    | devopplus |        NULL |
    | 10 | devopplus    | devopplus |        NULL |
    j'ai testé avec un type 1 sans quote, amis cela me génère aussi un NULL

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    {"nameMatiere": "devopplus", "route": "devopplus", "sommaire_id":1}
    voici mon entité sommmaire:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
     
    public class Sommaire implements Serializable {
        @Id
        @GeneratedValue(strategy = GenerationType.IDENTITY)
        private Long id;
        @Column(unique = true)
        private String nameSommaire;
        private String route;
        @OneToMany(mappedBy="sommaire",fetch = FetchType.EAGER)
        //un sommaire peut avoir plusieur matieres
        private Collection<Matiere> matieres = new ArrayList<>();
     
    }
    comment je dois insérer correctement ma donnée ?

    merci de vos réponses

  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
    C'est quelle entity que tu persistes ?
    N'oubliez pas de consulter les FAQ Java et les cours et tutoriels Java

  3. #3
    Membre chevronné Avatar de jeffray03
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Juillet 2008
    Messages
    1 501
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Allemagne

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Juillet 2008
    Messages : 1 501
    Points : 2 120
    Points
    2 120
    Par défaut
    salut ,

    moi j´aurais fait comme ceci:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
     
    public class Sommaire implements Serializable {
        @Id
        @GeneratedValue(strategy = GenerationType.IDENTITY)
        private Long id;
        @Column(unique = true)
        private String nameSommaire;
        private String route;
        @OneToMany(cascade=CascadeType.ALL, fetch = FetchType.EAGER)
        @JoinColumn(name = "sommaireid")
        private Collection<Matiere> matieres = new ArrayList<>();
    et

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
    public class Matiere implements Serializable{
        @Id 
        @GeneratedValue(strategy = GenerationType.IDENTITY) 
        private Long id;
        private String nameMatiere;
        private String route;
     
    }
    la tu auras dans la table Matiere ceci :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    | id | name_matiere | route     | sommaire_id |
    +----+--------------+-----------+-------------+
    |  1 | reseaux      | reseaux   |           1 |
    |  2 | linux        | linux     |           1 |
    Bonne journée

    Eric

  4. #4
    Membre confirmé

    Profil pro
    Inscrit en
    Août 2008
    Messages
    1 191
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2008
    Messages : 1 191
    Points : 595
    Points
    595
    Par défaut
    merci de vos réponse, j'ai testé la solution de cascade mais j'ai une erreur lors de la compilation:
    Code java : 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
    31
    32
    33
    34
     
    @Entity
    @Data @NoArgsConstructor @AllArgsConstructor @ToString
     
    public class Matiere implements Serializable{
        @Id @GeneratedValue(strategy = GenerationType.IDENTITY) 
        private Long id;
        private String nameMatiere;
        private String route;
        //une matiere appartient à un sommaire
        /*
        @ManyToOne
        @JoinColumn(name="sommaire_id")
        private Sommaire sommaire;
        */
    }
     
     
     
    @Entity @Data @NoArgsConstructor @AllArgsConstructor @ToString
     
    public class Sommaire implements Serializable {
        @Id
        @GeneratedValue(strategy = GenerationType.IDENTITY)
        private Long id;
        @Column(unique = true)
        private String nameSommaire;
        private String route;
        //un sommaire peut avoir plusieur matieres
        @OneToMany(cascade=CascadeType.ALL, fetch = FetchType.EAGER)
        @JoinColumn(name="sommaire_id")
        private Collection<Matiere> matieres = new ArrayList<>();
     
    }
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    java.lang.Error: Unresolved compilation problems:
            The method save(S) in the type CrudRepository<Matiere,Long> is not applicable for the arguments (Matiere)
            The constructor Matiere(null, String, String, Sommaire) is undefined
    Code java : 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
     
    @Entity @Data @NoArgsConstructor @AllArgsConstructor @ToString
     
    public class Sommaire implements Serializable {
        @Id
        @GeneratedValue(strategy = GenerationType.IDENTITY)
        private Long id;
        @Column(unique = true)
        private String nameSommaire;
        private String route;
        //un sommaire peut avoir plusieur matieres
        @OneToMany(cascade=CascadeType.ALL, fetch = FetchType.EAGER)
     
        private Collection<Matiere> matieres = new ArrayList<>();
     
    }

    je remet mes 2 entités de mon ide:

    Nom : entite.png
Affichages : 2260
Taille : 45,1 Ko

    par contre je me dit que la donnée est à NULL car spring ne s'attend pas à recevoir directement une clé étrangère par un int puisque c'est un objet de type

    peut être que je suis contraint dans mon dao de mettre une fonction qui enregistre directement le numéro du numéro sommaire ??

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
    @RepositoryRestResource
    public interface MatiereRepository extends JpaRepository<Matiere, Long> {
        public Matiere findByNameMatiere(String nameMatiere);
     
    public insertIdSommaire(id_sommaire){
    ...
    }
    }
    si je test ceci en passant par string main
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    		Sommaire s1 =new Sommaire(null, "devops", "devops",null);
    		sommaireRepository.save(s1);
    		matiereRepository.save(new Matiere(null, "reseaux", "reseaux",s1));
     
    		matiereRepository.save(new Matiere(null, "jenkins", "jenkins",1));
    il refusera le id_sommaire = 1 de la nouvelle matière "jenkins".

  5. #5
    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
    D'après ton code, tu persistes donc Matière, c'est donc matière qui doit avoir l'attribut "cascade".
    N'oubliez pas de consulter les FAQ Java et les cours et tutoriels Java

  6. #6
    Membre confirmé

    Profil pro
    Inscrit en
    Août 2008
    Messages
    1 191
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2008
    Messages : 1 191
    Points : 595
    Points
    595
    Par défaut
    merci de ta réponse,

    je pense que pour le moment je suis perdu.
    en regardant ce lien j'ai une explication de maitre et esclave d'entité

    http://blog.paumard.org/cours/jpa/ch...-relation.html

    j'ai donc schématiser cela en appliquant à mon problème:

    Nom : manytoone.png
Affichages : 2236
Taille : 14,9 Ko

    est ce que ce que j'ai dessiner et correcte ? car je pense qu'avant de coder correctement mes classes je dois mieux comprendre le oneToMany,
    et mettre le chose dans l'ordre.
    car je pense que je mélange les pinceaux .

  7. #7
    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
    Disons que le plus simple est de voir ces annotations comme ceci :

    EntitéA
    @OneToMany Set<EntiteB>

    veut dire que ton EntiteA référence une liste d'EntitéB


    EntiteB
    @ManyToOne EntiteA

    veut dire que ton EntitéB référence une EntitéA

    L'attribut Cascade se met de côté de l'entité qui est maître de l'information.


    Prenons un exemple : Une facture et ses lignes de factures
    Dans ce cas, la ligne sans facture n'a pas de sens, il convient donc d'utiliser la facture pour persister son Set de ligne.
    On mettra donc un attribut Cascade sur l'annotation @OneToMany

    Autre exemple : Un Travail référence un Utilisateur
    Dans ce cas, c'est le Travail qu'on persiste, l'utilisateur est certainement géré par un autre programme.
    On mettra aucune Cascade sur l'annotation @ManyToOne de Travail

    C'est plus clair ?
    N'oubliez pas de consulter les FAQ Java et les cours et tutoriels Java

  8. #8
    Membre confirmé

    Profil pro
    Inscrit en
    Août 2008
    Messages
    1 191
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2008
    Messages : 1 191
    Points : 595
    Points
    595
    Par défaut
    Merci de ton explication,
    donc mon dessin avec ton exemple devient:

    Nom : persiste.png
Affichages : 2340
Taille : 21,3 Ko

    Sinon je n'avais pas encore eu l'occasion de rencontrer
    1:n sera toujour @oneToMany ? schématiquement 1:p n'existe pas ?

    et mappedBy, dans mon cas il ne faut pas le mettre ?

    Est ce bon si je dis que sommaire est mon entité maître et que je l'écris comme ceci :

    Code java : 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
     
    public class Sommaire implements Serializable {
        @Id
        @GeneratedValue(strategy = GenerationType.IDENTITY)
        private Long id;
     
     
        @Column(unique = true)
        private String nameSommaire;
        private String route;
     
            //un sommaire peut avoir plusieur matieres
            @OneToMany(cascade=CascadeType.ALL, fetch = FetchType.EAGER)
            private Collection<Matiere> matieres = new ArrayList<>();
     
    }

    J'ai juste testé pour le moment l'enregistrement d'un sommaire, ce qui me donne :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    		Sommaire s1 =new Sommaire(null, "name-devops", "route-devops",null);
    		sommaireRepository.save(s1);
    ma table de donnée:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     
    select * from sommaire;
    +----+---------------+--------------+
    | id | name_sommaire | route        |
    +----+---------------+--------------+
    |  1 | name-devops   | route-devops |
    +----+---------------+--------------+
    1 row in set (0.00 sec)
    une fois que mon entité maître est ok, j'écrirais mon entité esclave.

  9. #9
    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
    Citation Envoyé par keokaz Voir le message
    1:n sera toujour @oneToMany ? schématiquement 1:p n'existe pas ?
    Je ne comprends pas ta notion 1:p, peux-tu préciser ?

    Pour une relation 1:n, généralement, c'est @OneToMany qui est utilisée mais dans le cas où tu passerais par une table de relation pour enregistrer le lien, il faudrait utiliser @ManyToMany.

    La différence vient du "masquage" de la table de relation dans les entités, en gros ceci :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    TableA(id)<..........TableRelationAB(idA,idB)..........>TableB(id)
    Et ton entiteA liée à TableA intégrerait un Set<EntiteB liée à TableB> (en masquant TableRelationAB).

    Bien sûr, ça n'a pas de sens quand la relation est porteuse...



    Dans le cas d'une relation Maître-Esclave, on pourrait se passer de @ManyToOne dans l'entité Esclave si l'entité Maître existait au préalable mais souvent, ce n'est pas le cas.
    Dans l'exemple de la facture et de ses lignes, on n'enregistre pas la facture sans ligne, du coup, si on n'avait mis uniquement la clé primaire de Facture dans Ligne, on n'aurait pas sa valeur (dans le cas d'une clé auto-incrémentale) au moment de persister les lignes et ça se planterait.
    En passant pas l'objet représentant l'entité Facture dans l'entité Ligne, JPA (Hibernate, EclipseLink...) est capable de faire les choses tout seul...
    N'oubliez pas de consulter les FAQ Java et les cours et tutoriels Java

  10. #10
    Membre confirmé

    Profil pro
    Inscrit en
    Août 2008
    Messages
    1 191
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2008
    Messages : 1 191
    Points : 595
    Points
    595
    Par défaut
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    on n'enregistre pas la facture sans ligne
    Je pense que mon cas, je n'oblige pas à créer tout de suite une matière sans avoir créer un sommaire.
    une matière peut par exemple être tout seul
    dans main, je créer donc mon sommaire comme ceci
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    		Sommaire s1 =new Sommaire(null, "name-devops", "route-devops",null);
    le null serai là pour dire que le sommaire n'a pas encore de matière?

    voici mon entité matière:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     
    @Entity
    @Data @NoArgsConstructor @AllArgsConstructor @ToString
     
    public class Matiere implements Serializable{
        @Id @GeneratedValue(strategy = GenerationType.IDENTITY) 
        private Long id;
        private String nameMatiere;
        private String route;
    }
    du coup si j'enregistre une nouvelle matière j'ai comme code :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    		matiereRepository.save(new Matiere(null, "name-dao", "route-dao"));
    je n'ai pas d'erreur de compilation et mes données sont ok:

    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
     
     select * from sommaire;
    +----+---------------+--------------+
    | id | name_sommaire | route        |
    +----+---------------+--------------+
    |  1 | name-devops   | route-devops |
    +----+---------------+--------------+
     
    select * from matiere;
    +----+--------------+-----------+
    | id | name_matiere | route     |
    +----+--------------+-----------+
    |  1 | name-dao     | route-dao |
    +----+--------------+-----------+
    1 row in set (0.00 sec)
    Maintenant quelle serais mon choix alors ma 4ème colonne de la table matière ??
    - je ne dois pas utilisé l'entité esclave ? puisque je souhaite enregistrer une matière sans passer par l'entité sommaire ? (ou avoir la possibilité aussi d'enregistrer en même temps le sommmaire + la matière).
    - est ce que je dois dans ce cas là utiliser @manyToMany ? et comme tu l'as précisé d'avoir une table de clés étrangères pour faire la relation

    le but étant de facilité l'enregistrement d'une matière dès que je demande un traitement de type POST.
    Pour le moment quand je souhaite enregistrer une nouvelle matière, mon formulaire demande de sélectionner le numéro du sommaire afin de le récupérer l'information pour lié la nouvelle matière à un sommaire.

    pour
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    Je ne comprends pas ta notion 1:p, peux-tu préciser ?
    dans le blog il utilise cette annotation et indique qu'il y a 4 types de relation

    Code java : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     
    Tout comme en SQL, on peut définir quatre types de relations entre entités JPA :
     
    relation 1:1 : annotée par @OneToOne ;
     
    relation n:1 : annotée par @ManyToOne ;
     
    relation 1:p : annotée par @OneToMany ;
     
    relation n:p : annotée par @ManyToMany.

    juste visuellement dans un schema si je dessine une entité et à coté j'écris sa relation,
    que l'annotation de relation qu'il soit à droite ou à gauche , j'aurais toujours un 1:p ? (on pourrais par exemple se dire que si j'inverse l'annotation de la relation le 1:p deviendrais 1:p).
    au début je pensais que on mettait juste la lettre n pour dire plusieurs (n:1 pour oneToMany, et 1:n pour ManyToOne), mais le p est apparu est venu complexifier les choses .

  11. #11
    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
    Alors, pour les différences entre @OneToOne et @ManyToOne c'est assez simple :

    EntiteA @OneToOne EntiteB : il ne peut y avoir qu'un enregistrement de EntiteA référençant EntiteB

    EntiteA @ManyToOne EntiteB : il peut y avoir plusieurs EntiteA référençant EntiteB


    En DB, dans les 2 cas, tu auras une clé étrangère dans la table représentant EntiteA vers la table représentant EntiteB.
    La différence serait que pour @OneToOne, tu aurais un index unique sur la clé étrangère.
    Exemple :
    Code SQL : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    @OneToOne
     
    create table TableA(
       UID INTEGER AS IDENTIFIER NOT NULL,
       UID_TABLEB INTEGER,
       ...
       primary key(UID),
       unique index UnNomIndex (UID_TABLEB)
    )
    Code SQL : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    @ManyToOne
     
    create table TableA(
       UID INTEGER AS IDENTIFIER NOT NULL,
       UID_TABLEB INTEGER,
       ...
       primary key(UID)
    )
    N'oubliez pas de consulter les FAQ Java et les cours et tutoriels Java

  12. #12
    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
    Pour ta problématique, je ferais ceci :

    1- Sommaire avec un Set<Matiere> Cascade.ALL
    2- Matiere avec un Objet Sommaire en @OneToOne si une matière ne peut être que dans 1 sommaire
    ou
    Matiere avec un Objet Sommaire en @ManyToOne si une matière peut être dans plusieurs sommaires


    Si tu persistes un sommaire, ça persistera les matières et si tu persistes une matière, je ne vois pas l'intérêt de persister le sommaire.
    A vu de nez, ça devrait fonctionner comme ça
    N'oubliez pas de consulter les FAQ Java et les cours et tutoriels Java

  13. #13
    Membre actif
    Avatar de ryankarl65
    Homme Profil pro
    Data Engineer
    Inscrit en
    Juillet 2013
    Messages
    104
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Val d'Oise (Île de France)

    Informations professionnelles :
    Activité : Data Engineer

    Informations forums :
    Inscription : Juillet 2013
    Messages : 104
    Points : 278
    Points
    278
    Par défaut
    J'aimerais apporter une solution au probleme initial.
    mais je sais pas s'il a été resolu ou pas.
    c'est bon pour ton probleme ?
    Shakespeare: "Je me sens toujours heureux, vous savez pourquoi...?
    Parce que je n'attends rien de personne... Les attentes font toujours mal, la vie est courte. Aimez votre vie, soyez heureux, gardez le sourire et souvenez vous: Avant de parler écoutez, Avant d'écrire réfléchissez, Avant de prier pardonnez, Avant de blesser considérez l'autre, Avant de déteste aimez... Et avant de mourir vivez"

  14. #14
    Membre confirmé

    Profil pro
    Inscrit en
    Août 2008
    Messages
    1 191
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2008
    Messages : 1 191
    Points : 595
    Points
    595
    Par défaut
    pour le moment je n'ai pas résolut le problème, car je n'ai pas encore testé et compris comment on enregistre à travers JPA correctement une donnée qui est lié à une entité.

    je récapitule la ligne de code qui va me générer un problème de compilation:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    matiereRepository.save(new Matiere(null, "name-dao", "route-dao", ???));
    si dans ??? je mets null cela va bien enregistrer un sommaire puis une matière.
    avant d'enregistrer la matière dans ma méthode main j'enregistre un nouveau sommaire puis avec l'injection de dépendance sommaire j'ajoute la matière

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    		Sommaire s1 =new Sommaire(null, "name-devops", "route-devops",null);
    matiereRepository.save(new Matiere(null, "name-dao", "route-dao", S1));
    Le "S1" passe bien en paramètre.

    Mon problème initial est que j'ai déjà un sommaire qui existe, je souhaite ajouter une matière , si je tente ceci:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    //ce code va être lancé dans le cas je demande une requête de type POST
    matiereRepository.save(new Matiere(null, "name-dao", "route-dao", XX));
    XX est un nombre qui correspond à une cléf primaire(auto-incrémenter) qui détermine le numéro de la matière.
    Mais le compilateur le refuse , à première vu on dirait que c'est normal puisque que le paramètre XX doit être un type "Sommaire".

    La question qu'on se pourrais se poser:

    est ce qu'on peut utiliser
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    matiereRepository.save(new Matiere(null, "name-dao", "route-dao", S?));
    - est qu'on à le droit de faire un matiereRepository.save
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    matiereRepository.save(new Matiere(null, "name-dao", "route-dao", S1));
    spring boot du moins JPA sait t'il que si j'appelle ci dessous cette ligne si que le sommaire "name-dao" existe déjà, donc il ne va pas la créer mais récupérer son entité et pouvoir l'utiliser par la suite par exemple
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    Sommaire existe_deja =new Sommaire(null, "name-devops", "route-devops",null);
    matiereRepository.save(new Matiere(null, "name-dao", "route-dao", existe_deja));

    jeffray03 me propose d'utiliser casacade, ce qui serais logique puisque avec cascade ,
    j'ai modifier mon code mais

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
     @OneToMany(cascade=CascadeType.ALL, fetch = FetchType.EAGER)
    en testant son code j'ai une erreur de compilation, il n'accepte l'annotation que j'ai modifier

    OButterlin à analyser mon code et m'indique qu'il faut "persister" à sommaire et pas à matière(on persiste du coté maître).
    dans le code de jeffrey comme il n'y pas d'annotation qui détermine la liaison @manyToOne matière est l'esclave.

    je dispose de 2 choix

    - soit d'utiliser maitre=> esclave = sommaire =@oneToMany matiere=pas d'annotation
    - soit d'utiliser sommaire =@oneToMany matiere=@manyToMany (ce qui va générer une 3èmes tables qui récupère les clés étrangère de sommaire et matière

    Mais si je fais l'une des 2 choix, j'aurai je pense pour le moment toujours ce problème comment insérer correctement une nouvelle matière

    - insérer en même temps un sommaire et une nouvelle matière
    - insérer seulement une matière sans donner le sommaire (dans ma conception on peut générer une matière sans pour autant connaître son sommaire, je donne cette liberté au cas ou
    je souhaite affiché cette matière seul sans contrainte).

    Pensez-vous que j'ai compris déjà pourquoi cela ne fonctionne pas ? (ou que je sois à côté de la plaque )
    je vais testé la dernière réponse d'OButterlin

  15. #15
    Membre confirmé

    Profil pro
    Inscrit en
    Août 2008
    Messages
    1 191
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2008
    Messages : 1 191
    Points : 595
    Points
    595
    Par défaut
    j'ai testé:

    donc matière:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
     
     
    public class Matiere implements Serializable{
        @Id @GeneratedValue(strategy = GenerationType.IDENTITY) 
        private Long id;
        private String nameMatiere;
        private String route;
        @OneToOne
        private Sommaire sommaire;
     
    }
    sommaire:

    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
     
    public class Sommaire implements Serializable {
        @Id
        @GeneratedValue(strategy = GenerationType.IDENTITY)
        private Long id;
     
        @Column(unique = true)
        private String nameSommaire;
        private String route;
     
            //un sommaire peut avoir plusieur matieres
            @OneToMany(cascade=CascadeType.ALL, fetch = FetchType.EAGER)
            private Collection<Matiere> matieres = new ArrayList<>();
     
    }
    je me retrouve toujours avec sommaire_id = NULL après avoir testé une requête type post:
    Nom : rest.png
Affichages : 2143
Taille : 19,3 Ko


    Code sql : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
    select * from matiere;
    +----+--------------+------------+-------------+
    | id | name_matiere | route      | sommaire_id |
    +----+--------------+------------+-------------+
    |  1 | name-dao     | route-dao  |           1 |
    |  2 | nom matiere  | rourte-mat |        NULL |
    +----+--------------+------------+-------------+
    2 rows in set (0.00 sec)

    Peut être que je dois créer une fonction qui enregistre une nouvelle matière dans mon repository matiere et que cela ne sera pas tout seul par le saint-esprit ?

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     
    @RepositoryRestResource
    public interface MatiereRepository extends JpaRepository<Matiere, Long> {
        public Matiere findByNameMatiere(String nameMatiere);
     
        public addMatiereId(name,route,idSommaire){
               entityManager.createNativeQuery("INSERT INTO matiere (name,route,idSommaire) VALUES ("name","routeidSommaire)")
          .executeUpdate();
        }  
    }

  16. #16
    Membre confirmé

    Profil pro
    Inscrit en
    Août 2008
    Messages
    1 191
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2008
    Messages : 1 191
    Points : 595
    Points
    595
    Par défaut
    j'ai commencé à essayer de récupérer le numéro du sommaire et sa matière.
    j'ai donc créer une classe service qui va récupérer le numéro du sommaire et le nom de la nouvelle matière:

    Code java : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
     
    @RestController
    public class MenuRestService{
        @Autowired
        private MatiereRepository matiereRepository;
        @Autowired
        private SommaireRepository SommaireRepository;
     
        @RequestMapping(value="/new-matiere", method=RequestMethod.POST)
        private void recup( @RequestBody Map<String, Object> publication) {
           System.out.println("enregistre la nouvelle matiere qui appartient à sommaire id "+publication);
        }
     
    }

    je fait donc une requête de type POST, et le retour j'obtient ceci:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    enregistre la nouvelle matiere qui appartient à sommaire id {matiere=boot, id=1}
    Maintenant que du côté backend je récupère le numéro du sommaire et le nom de la nouvelle matière, comment je fais pour les exploité ?

    - je travaille directement sur cette donnée ?

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
     {matiere=boot, id=1}
    - ou je dois créer une interface "newSommaire" et une implémentation newSommaire affin que les informations puisse être exploiter sous forme de cette objet ?
    ce qui changerai le paramètre ma méthode "recup" ??

    Code java : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
        private void recup( @RequestBody NewSommaire publication) {

  17. #17
    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 comprends pas trop ta problématique, dans tous les cas, dans ton IHM de création de matière, tu devrais avoir la référence du sommaire à utiliser (sous forme d'une combo ou liste), du coup, quelque soit la forme, UID ou code, tu as l'info utile, inutile d'avoir une fonction qui va récupérer de nouveau.

    Par contre, en fonction de ce que tu auras dans ton objet d'échange entre l'IHM et la DAO, il faudra peut-être faire un traitement.
    Si ton entité Matiere référence un objet Sommaire et que tu as l'ID du sommaire, alors il faudra récupérer l'entité Sommaire correspondant à l'ID.
    Mais si ton entité Matiere référence l'ID sommaire, alors tu as tout ce qu'il faut pour persister.
    N'oubliez pas de consulter les FAQ Java et les cours et tutoriels Java

  18. #18
    Membre confirmé

    Profil pro
    Inscrit en
    Août 2008
    Messages
    1 191
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2008
    Messages : 1 191
    Points : 595
    Points
    595
    Par défaut
    côté front-end angular je récupère tous les sommaires, et je sélectionne le sommaire afin d'avoir cette infor et la renvoyer au backend spring boot afin d'enregistrer au bon endroit

    Code javascript : 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
     
    <form #f="ngForm" (ngSubmit)="nwPub(f.value)">
        <div class="erreur" *ngIf="mode==1">
            <strong>erreur de formulaire</strong>
        </div>
     
        <h4>Dans quelle catégorie du sommaire ? </h4>
        <mat-form-field>
          <mat-select placeholder="ajouter dans quel sommaire ?" >
            <mat-option 
              (onSelectionChange)="changeIdSommaire($event)"
              *ngFor="let menu of menu_hz._embedded.sommaires" 
              [value]="menu">
              {{menu.nameSommaire }}
            </mat-option>
          </mat-select>
        </mat-form-field>
        <br />
        <mat-form-field>
                <input ngModel="" matInput placeholder="nouvelle matiere" name="matiere" required>
              </mat-form-field>
        <br/>
        <button mat-raised-button type="submit" color="primary"  [disabled]="!f.valid">Enregistrer</button>
    </form>

    une fois mon choix fait, et remplir le nom de la matière je fait la demande au backend

    Code javascript : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
     
      nwPub(pub) {
        pub.idSommaire = this.idSommaireSelected;
     
     
        let req =  this.http.post("http://localhost:8181/new-matiere" ,pub, { headers: new HttpHeaders({ 'Authorization': localStorage.getItem('token') }) } );
        req.subscribe(data=>{
          console.log(data);
        });
     
      }

    j'envoie ceci:

    Code html : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    {"matiere":"test","idSommaire":"1"}

    Après peut être que je m'y prend mal (ou que simplement je ne sais pas le faire car je suis encore un newbee) ? que je dois essayer de récupérer directement l"objet du numéro de sommaire que j'ai sélectionné ?
    Mais c'est vrai que comme j'ai déjà fait une requête qui demande tous les sommaires, c'est peut être idiot de refaire une autre requête pour obtenir le sommaire, mais cette fois ci d'avoir le sommaire que j'ai sélectionner.

    niveau du côté backend je comptais faire ceci:

    Code java : 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
     
       ObjectMapper objectMapper = new ObjectMapper();
     
            try {
     
                Menu menu = objectMapper.readValue(publication, Menu.class);
                Number idSommaire = menu.getIdSommaire();
                System.out.println("==>" + idSommaire);
     
                Sommaire sx = sommaireRepository.findById(idSommaire); //je récupère le numéro du sommaire
                System.out.println(sx);
     
     
     matiereRepository.save(new Matiere(null, "new", "new",sx));
     
     
     
            } catch (IOException e) {
                e.printStackTrace();
            }

    et là je retombe sur mes pattes de débutant pour voir utiliser mon repository seul :

    Code java : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
     matiereRepository.save(new Matiere(null, "new", "new",sx));

    pour le moment je n'ai pas réussi enregistrer une nouvelle matiere
    voici mon sx
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    ==>1
    SX ==>Optional[Sommaire(id=1, nameSommaire=name-devops-z, route=route-devops-z, matieres=[])]

  19. #19
    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
    Tu devrais faire quelque chose comme ceci (c'est pour un iSeries mais bon, l'idée est là)
    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
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    @Entity
    @Table(name = "ASOMMAIRE", schema="OBU")
    public class ASommaire
    {
        private Integer uid;
        private String libelle;
        private Set<AMatiere> matieres;
     
        public ASommaire()
        {
            super();
        }
     
        public ASommaire(Integer uid)
        {
            super();
            this.uid = uid;
        }
     
        public ASommaire(Integer uid, String libelle, Set<AMatiere> matieres)
        {
            super();
            this.uid = uid;
            this.libelle = libelle;
            this.matieres = matieres;
        }
     
        @Id
        @Column(name = "UID", unique = true, nullable = false)
        @GeneratedValue(strategy=GenerationType.IDENTITY)
        public Integer getUid()
        {
            return uid;
        }
     
        public void setUid(Integer uid)
        {
            this.uid = uid;
        }
     
        @Column(name = "LIBELLE")
        public String getLibelle()
        {
            return libelle;
        }
     
        public void setLibelle(String libelle)
        {
            this.libelle = libelle;
        }
     
        @OneToMany(fetch = FetchType.EAGER, cascade=CascadeType.ALL, mappedBy="sommaire")
        public Set<AMatiere> getMatieres()
        {
            return matieres;
        }
     
        public void setMatieres(Set<AMatiere> matieres)
        {
            this.matieres = matieres;
        }
    }
    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
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    @Entity
    @Table(name = "AMATIERE", schema="OBU")
    public class AMatiere
    {
        private Integer uid;
        private String libelle;
        private ASommaire sommaire;
     
        public AMatiere()
        {
            super();
        }
     
        public AMatiere(Integer uid)
        {
            super();
            this.uid = uid;
        }
     
        public AMatiere(Integer uid, String libelle, ASommaire sommaire)
        {
            super();
            this.uid = uid;
            this.libelle = libelle;
            this.sommaire = sommaire;
        }
     
        @Id
        @Column(name = "UID", unique = true, nullable = false)
        @GeneratedValue(strategy=GenerationType.IDENTITY)
        public Integer getUid()
        {
            return uid;
        }
     
        public void setUid(Integer uid)
        {
            this.uid = uid;
        }
     
        @Column(name = "LIBELLE")
        public String getLibelle()
        {
            return libelle;
        }
     
        public void setLibelle(String libelle)
        {
            this.libelle = libelle;
        }
     
        @ManyToOne
        @JoinColumn(name = "UID_SOMMAIRE")
        public ASommaire getSommaire()
        {
            return sommaire;
        }
     
        public void setSommaire(ASommaire sommaire)
        {
            this.sommaire = sommaire;
        }
    }
    et pour le code d'utilisation tu as :
    Création préalable du sommaire puis ajouts successifs de matiere (ou dans ton cas recherche du sommaire par son id)
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
            ASommaire sommaire = new ASommaire(null, "Sommaire 1", null);
            getEntityManager().persist(sommaire);
            AMatiere matiere = new AMatiere(null, "Matiere 1", sommaire);
            getEntityManager().persist(matiere);        
            AMatiere matiere2 = new AMatiere(null, "Matiere 2", sommaire);
            getEntityManager().persist(matiere2);
    ou création du sommaire avec ses matières
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
            ASommaire sommaire = new ASommaire(null, "Sommaire 2", new HashSet<>());
            sommaire.getMatieres().add(new AMatiere(null, "Matiere 21", sommaire));
            sommaire.getMatieres().add(new AMatiere(null, "Matiere 22", sommaire));
            getEntityManager().persist(sommaire);
    N'oubliez pas de consulter les FAQ Java et les cours et tutoriels Java

  20. #20
    Membre confirmé

    Profil pro
    Inscrit en
    Août 2008
    Messages
    1 191
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2008
    Messages : 1 191
    Points : 595
    Points
    595
    Par défaut
    Merci de m'avoir aidé,

    finalement j'ai trouvé ce que je souhaite, c'était finalement très simple et super rapide avec spring boot,
    voici mon entité sommaire:

    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
     
    @Entity @Data @NoArgsConstructor @AllArgsConstructor @ToString
     
    public class Sommaire implements Serializable {
        @Id
        @GeneratedValue(strategy = GenerationType.IDENTITY)
        private Long id;
     
        @Column(unique = true)
        private String nameSommaire;
        private String route;
     
            //un sommaire peut avoir plusieur matieres
            @OneToMany(cascade=CascadeType.ALL, fetch = FetchType.EAGER)
            private Collection<Matiere> matieres = new ArrayList<>();
     
    }
    voici mon entité matiere:
    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
     
    @Entity
    @Data
    @NoArgsConstructor
    @AllArgsConstructor
    @ToString
     
    public class Matiere implements Serializable {
        @Id
        @GeneratedValue(strategy = GenerationType.IDENTITY)
        private Long id;
        private String nameMatiere;
        private String route;
        @OneToOne
        private Sommaire sommaire;
     
    }
    Pour enregistrer une matière relié un sommaire il suffisait tout simplement faire cette requête en POST:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    http://localhost:8181/matieres/
    et envoyé le donnée comme ceci en respectant le nom des champs des attributs:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    {"nameMatiere":"boot","route":"route", "sommaire":"http://localhost:8181/matieres/1"}
    j'avais tout ce qu'il fallait et pas besoin de créer cette fonction:

    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
     
     
        @RequestMapping(value = "/new-matiere", method = RequestMethod.POST)
        private void recup(@RequestBody String publication) {
     
            ObjectMapper objectMapper = new ObjectMapper();
     
            try {
     
                Menu menu = objectMapper.readValue(publication, Menu.class);
                Long idSommaire = (long) menu.getIdSommaire();
                System.out.println("==>" + idSommaire);
     
                Optional<Sommaire> sx = sommaireRepository.findById(idSommaire);
                System.out.println("SX ==>"+sx);
             //   matiereRepository.save(new Matiere(null, "new", "new",sx));
     
     
     
            } catch (IOException e) {
                e.printStackTrace();
            }
     
        }
    en plus d'avoir ajouter pour rien cette fonction, j'ai du encore ajouter une ligne supplémentaire dans spring security.

    et le résultat est maintenant correcte et n'est pas à NULL:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     
    select * from matiere;
    +----+--------------+-------+-------------+
    | id | name_matiere | route | sommaire_id |
    +----+--------------+-------+-------------+
    |  1 | boot           | root    |           1 |
    +----+--------------+-------+-------------+
    1 row in set (0.00 sec)
    j'ai pas assez réfléchis à utiliser spring-boot pour le micro service et laisser spring boot tout gérer, la difficulté c'est de maîtriser la relation entres les entités.

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Réponses: 5
    Dernier message: 18/08/2016, 17h47
  2. Réponses: 0
    Dernier message: 06/12/2015, 09h14
  3. Réponses: 4
    Dernier message: 16/04/2014, 16h17
  4. Réponses: 1
    Dernier message: 05/06/2012, 15h10
  5. Réponses: 3
    Dernier message: 06/12/2010, 15h59

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