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

Persistance des données Java Discussion :

Gestion Base de donnée en mémoire


Sujet :

Persistance des données Java

  1. #1
    Membre habitué
    Profil pro
    Inscrit en
    Mai 2010
    Messages
    143
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2010
    Messages : 143
    Points : 127
    Points
    127
    Par défaut Gestion Base de donnée en mémoire
    Bonjour,

    J'ai besoin de votre aide car j'ai des problèmes de mapping.

    On m'a donné un projet dans lequelle je dois implémenter une méthode qui filtre les résultats.

    Le projet est un lisiting de concerts avec 3 tables Event(Evenement) Band(groupe) Member(Membres du groupe)

    Dans le readme il est écrit "* It uses HSQLDB as an in-memory database."

    Dans le projet il y a un fichier sql qui semble insérer les données

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    INSERT INTO EVENT (ID, TITLE, IMG_URL) VALUES (1000, 'GrasPop Metal Meeting', 'img/1000.jpeg');
    INSERT INTO BAND(ID, NAME) VALUES (1000, 'Pink Floyd');
    INSERT INTO MEMBER(ID, NAME) VALUES (1001,'Queen Frankie Gross (Fania)');
    Ils ont aussi créé des tables pour gérer les relations (un événement concerne 1 ou plusieurs groupes, un groupe contient un ou plusieurs membres)

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    INSERT INTO EVENT_BANDS(EVENT_ID, BANDS_ID) VALUES (1000, 1000);
    INSERT INTO BAND_MEMBERS(BAND_ID, MEMBERS_ID) VALUES (1000,1001);
    Ils ont également mis dans le projet les classes java correspondant aux 3 tables Event.java Band.java et Member.java

    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
     
    @Entity
    public class Event {
        @Id
        @GeneratedValue(strategy= GenerationType.AUTO)
        private Long id;
     
        private String title;
     
        private String imgUrl;
     
        @OneToMany(fetch=FetchType.EAGER)
         private Set<Band> bands;
     
        private Integer nbStars;
     
        private String comment;
     
    +getter et setters
    }
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
     
    @Entity
    public class Band {
     
        @Id
        @GeneratedValue(strategy = GenerationType.AUTO)
        private Long id;
     
        private String name;
     
        @OneToMany(fetch=FetchType.EAGER)
        private Set<Member> members;
     
    +getters et setters
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     
    @Entity
    public class Member {
        @Id
        @GeneratedValue(strategy = GenerationType.AUTO)
        private Long id;
     
        String name;
    Mon exercice consiste à récupérer les événements qui ont au moins un groupe contenant un membre ayant le nom passé en paramètre.

    Mon problème est que dans l'etat actuel des choses les relations entre les tables Event Band et Member semblent pas/mal modélisé car quand je récupère les events via un "Select e from Event" le resultat ne contient pas les band associé à l'event et lorsque je fais une jointure "Select e from Event e inner join Band b Inner join Member m" je ne reçois aucun résultat.

    J'ai essayé de modéliser la table EVENT_BANDS via une annotation jointable mais quand je le fais j'ai cette erreur :

    "a FOREIGN KEY constraint already exists on the set of columns: FKR606QG1GT3QH7R1ATB7I9K7MH in statement [alter table event_bands add constraint FKr606qg1gt3qh7r1atb7i9k7mh foreign key (event_id) references event]"

    Est-ce que vous savez comment je dois faire pour modéliser la table EVENT_BANDS(EVENT_ID, BANDS_ID) ?

  2. #2
    Membre éclairé

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

    Informations forums :
    Inscription : Janvier 2009
    Messages : 463
    Points : 897
    Points
    897
    Billets dans le blog
    5
    Par défaut
    JPA est un framework difficile qui demande une très bonne connaissance des concepts sous jacent à la BDD.

    Pour commencer, je vais répondre à un commentaire d'hier:
    https://www.developpez.net/forums/d2...hibernate-jpa/


    hibernate.ddl-auto: "update" signifie que Hibernate/JPA va mettre à jour la structure de la BDD. Cette option est pour moi à éviter.

    Pour en revenir au cœur du problème, il faut comprendre que JPA est un ORM (Object Relationnal Mapping).
    C'est un framework qui permet de faire le lien entre la BDD qui est relationnelle, et un modèle Java qui est objet.

    Les deux mondes n'ont pas le même socle théorique.

    Par exemple, le monde Java connait l'héritage qui est une notion qui n'existe pas en BDD.

    JPA permet d'avoir des classes avec héritage en BDD.

    Quand on fait du JPA, je recommande d'être très maniaque, psychorigide et vraiment vieux con.

    Ce qui me gène dans les classe montrées, c'est que le mapping n'est pas précisé, selon les principes énoncés précédemment (que l'on nommera la règle du vieux con).

    Par exemple, on a:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    private String title;
    On devrait à minima avoir:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    @Column(name = "TITLE")
    private String title;
    Voir en appliquant à fond la règle du vieux con:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    @Column(name = "TITLE",nullable=false,length=50)
    private String title;
    Certes, la règle du vieux con peut paraître excessive, mais Hibernate/JPA est un bon framework, mais l'erreur peut vite devenir chère, notamment au niveau des performances.

    C'est pour ça qu'une utilisation à bon escient de JPA/Hibernate demande d'avoir de bonnes notions en BDD.

    Dans le cas présent, c'est le mapping que je trouve incomplet.

    Tu en trouvera des exemple ici:
    https://bitbucket.org/philippegibaul...entity/entity/

  3. #3
    Membre habitué
    Profil pro
    Inscrit en
    Mai 2010
    Messages
    143
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2010
    Messages : 143
    Points : 127
    Points
    127
    Par défaut
    Citation Envoyé par PhilippeGibault Voir le message

    Certes, la règle du vieux con peut paraître excessive, mais Hibernate/JPA est un bon framework, mais l'erreur peut vite devenir chère, notamment au niveau des performances.

    Dans le cas présent, c'est le mapping que je trouve incomplet.

    Tu en trouvera des exemple ici:
    https://bitbucket.org/philippegibaul...entity/entity/
    Merci! Effectivement je trouvais ca bizarre qu'il n'y ait pas les @Column mais vu que ca avait l'air de fonctionner je n'ai pas osé touché au code qu'ils m'ont donné.

    J'ai fait la mise à jour et j'ai complété le code avec les bonnes annotations, merci pour tes exemples ça m'a permis de m'assurer que je ne faisait pas n'importe quoi.

    J'ai rééxécuté le code mais j'ai toujours la même erreur

    "a FOREIGN KEY constraint already exists on the set of columns: FK16R4CXS4Q8QF5IA7OE2ELGSGW in statement [alter table band_members add constraint FK16r4cxs4q8qf5ia7oe2elgsgw foreign key (band_id) references band]"

    J'ai l'impression qu'il essaye de recréer la table band_members juste parce que je l'ai mappé et vu qu'elle existe déjà il bloque

  4. #4
    Membre éclairé

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

    Informations forums :
    Inscription : Janvier 2009
    Messages : 463
    Points : 897
    Points
    897
    Billets dans le blog
    5
    Par défaut
    Le problème est un problème de mapping.
    Si on regarde la BDD, EVENT et BAND son des tables et EVENT_BANDS la table de jointure.

    Côté java, on a la classe Event qui a un Set de Band.
    Donc le mapping n'est pas @OneToMany mais @ManyToMany (qui est une jointure qui fera apparaître une table de jointure, ici EVENT_BANDS).

    etc...

  5. #5
    Membre habitué
    Profil pro
    Inscrit en
    Mai 2010
    Messages
    143
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2010
    Messages : 143
    Points : 127
    Points
    127
    Par défaut
    Citation Envoyé par PhilippeGibault Voir le message
    Le problème est un problème de mapping.
    Si on regarde la BDD, EVENT et BAND son des tables et EVENT_BANDS la table de jointure.

    Côté java, on a la classe Event qui a un Set de Band.
    Donc le mapping n'est pas @OneToMany mais @ManyToMany (qui est une jointure qui fera apparaître une table de jointure, ici EVENT_BANDS).

    etc...
    Ca fonctionne!! Tu avais tout à fait raison j'avais mal interprété la relation maintenant ca fonctionne nickel!

    Voici la méthode que j'ai faite pour rechercher en fonction d'un nom de membre (searchByNameOfMember) :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
     
    @Transactional(readOnly = false)
    public interface EventRepository extends CrudRepository<Event, Long> {
        @Query("select e From Event as e join e.bands as b join b.members as m where m.name like %:query%")
        List<Event> searchByNameOfMember(@Param("query")String query);
     
        void delete(Long eventId);
     
        List<Event> findAllBy();
     
    }
    Est-ce que cette façon de faire vous semble correct? (en terme de bonne pratique)


    J'ai entendu parlé d'une faille connu, l'injection sql je crois. En resumé c'est le fait de mettre directement la saisie de l'utilisateur dans la requête ce qui potentiellement permet à l'utilisateur de modifier la requête, est-ce que cette faille est présente dans ce code? Si oui comment je peux faire pour la supprimer?

  6. #6
    Membre éclairé

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

    Informations forums :
    Inscription : Janvier 2009
    Messages : 463
    Points : 897
    Points
    897
    Billets dans le blog
    5
    Par défaut
    Sur la faille, je peux te donner les peu de connaissances que je connais.

    Pour comprendre, il faut revenir au JDBC de base.

    Si tu fais du SQL comme :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    String sql = "SELECT nom FROM personne WHERE prenom='"+prenom+"'"
    Tu risques effectivement une injection SQL. Si par exemple prenom est de la forme:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    DELETE * FROM personne
    Tout ce qui est dans personne va être supprimé.

    Pour éviter ça, au lieu d'utiliser le le simple Statement, on utilise le PreparedStatement qui donne des paramètres.

    La requête devient:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    String sql = "SELECT nom FROM personne WHERE prenom=:prenom"
    On passe ainsi la valeur:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    pstmt.setString(1, prenom);
    Le prepared statement permet d'éviter l'injection de SQL.

    Dans ton cas, on peut légitimement penser que Spring et Hibernate sont "bien fait".

    Avec:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    @Query("select e From Event as e join e.bands as b join b.members as m where m.name like %:query%")
    On peut penser que derrière, Spring et Hibernate vont utiliser ses Prepared Statement. De fait, le risque d'injection SQL est moindre.

  7. #7
    Membre habitué
    Profil pro
    Inscrit en
    Mai 2010
    Messages
    143
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2010
    Messages : 143
    Points : 127
    Points
    127
    Par défaut
    Merci infiniment @PhilippeGibault j'avais pas beaucoup de connaissance sur le sujet et là je me sens beaucoup plus confiant grâce aux explications et exemples que tu m'a donné. Merci pour tout!

  8. #8
    Membre éclairé

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

    Informations forums :
    Inscription : Janvier 2009
    Messages : 463
    Points : 897
    Points
    897
    Billets dans le blog
    5
    Par défaut
    Il n'y a pas de quoi.

    Cordialement.

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

Discussions similaires

  1. Eclipse + gestion base de données
    Par fanette dans le forum Eclipse Java
    Réponses: 11
    Dernier message: 04/11/2018, 19h41
  2. Réponses: 5
    Dernier message: 05/11/2008, 08h10
  3. base de données en mémoire
    Par jose.ignacio.agata dans le forum Firebird
    Réponses: 12
    Dernier message: 14/12/2007, 16h25
  4. Gestion Base de Données
    Par deeperpaul dans le forum Excel
    Réponses: 1
    Dernier message: 13/12/2007, 20h51
  5. Réponses: 0
    Dernier message: 16/11/2007, 11h00

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