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

JPA Java Discussion :

Gros problème de compréhension pour "commiter" mes entity en base


Sujet :

JPA Java

  1. #1
    Membre du Club
    Profil pro
    Inscrit en
    Janvier 2009
    Messages
    109
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2009
    Messages : 109
    Points : 46
    Points
    46
    Par défaut Gros problème de compréhension pour "commiter" mes entity en base
    Bonjour à tous,

    J'ai comme entity : Book, OrderLine et Order.
    Une orderLine pointe sur un book et un order.

    Je n'arrive pas à mettre à jour mon orderLine, voici ma fonction avec des commentaires qui vont bien :

    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
    // Ajouter au panier
    	public Order addInOrder(Book book, int orderId) {
     
    		//Vérification si une ligne existe déjà avec ce livre
    		TypedQuery<OrderLine> queryName = em
    				.createQuery(
    						"Select cl From OrderLine cl Where order.id = :orderId AND book.isbn = :isbn",
    						OrderLine.class);
    		queryName.setParameter("orderId", orderId);
    		queryName.setParameter("isbn", book.getIsbn());
     
    		//List car getSimpleResult plante si il est vide...
    		List<OrderLine> orderLine = queryName.getResultList();
     
    		//Si il n'y a pas d'orderLine avec ce livre dans notre order
    		if (orderLine.size() == 0) {
     
    			//On rechercher notre order en base
    			TypedQuery<Order> queryName2 = em.createQuery(
    					"Select cl From Order cl Where cl.id = :orderId", Order.class);
    			queryName2.setParameter("orderId", orderId);
     
    			Order Order = queryName2.getSingleResult();
     
    			//on créé une nouvelle ligne
    			OrderLine orderline = new OrderLine();
    			orderline.setBook(book);
    			orderline.setQuantity(1);
     
    			// On fait en sorte que notre order ai cette ligne ? Automatique ?
    // Si je met un persist(orderline) j'ai l'erreur Caused by: javax.validation.UnexpectedTypeException: No validator could be found for type: java.lang.Integer
     
    		} else {
     
    			//Si on a trouvé une ligne avec ce livre, on rajoute 1 à la quantité de livre
    			int quantity = orderLine.get(0).getQuantity();
    			quantity++;
    			orderLine.get(0).setQuantity(quantity);
     
    			// Ne fait apparement rien sauf enlever la police rouge de ma quantité quand je pointe mon objet avec ma sourie
    			// comme si il l'avait mis à jour....
    			em.persist(orderLine.get(0));
    		}
     
    		// Récupération de notre order mis à jour... ou pas...
    		TypedQuery<Order> queryName2 = em.createQuery(
    				"Select cl From Order cl Where cl.id = :orderId", Order.class);
    		queryName2.setParameter("orderId", orderId);
     
    		//Récupération de l'ancien order, il n'est pas à jour, la ligne non plus.
    		Order order2 = queryName2.getSingleResult();
     
                    //Obligé de retourner notre order pour mettre notre Order de notre bean à jour ?
    		return order2;
     
    	}
    Pourtant ailleurs dans mon code, ça fonctionne :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    // Changer le mot de passe
    	public User updateMdp(User user, String mdp) {
    		User userM = em.find(User.class, user.getLogin());
    		userM.setMotDePasse(mdp);
    		return userM;
    	}
    Je suis en JTA donc pas de commit.

  2. #2
    Membre régulier
    Homme Profil pro
    Étudiant
    Inscrit en
    Janvier 2014
    Messages
    57
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Étudiant
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Janvier 2014
    Messages : 57
    Points : 93
    Points
    93
    Par défaut
    J'ai pas lu tout ton code mais a priori la deuxième méthode ne fonctionne pas non plus car tu ne fais que changer la valeur d'un attribut sur un objet Java, ça ne veut aucunement dire que l'entrée associée dans la BDD est mise à jour (tu pourras d'ailleurs l'observer de tes propres yeux en faisant un select de tes password avant et après l'appel à cette méthode).

    Pour ce faire, il faut utiliser em.merge(objetAMettreAJour). Attention à ce que cet objet ne pointe vers aucune Entity qui n'ait pas encore été persistée, si c'est le cas il faut d'abord les persister puis éventuellement merger, mais dans ton cas ça ira car tu récupères directement l'objet dans la base et ne lui change qu'un attribut simple.

    Cette remarque est aussi valable dans la première méthode : il faut faire appel à merge une fois que l'objet Java a été mis à jour.

  3. #3
    Membre du Club
    Profil pro
    Inscrit en
    Janvier 2009
    Messages
    109
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2009
    Messages : 109
    Points : 46
    Points
    46
    Par défaut
    Si justement ma méthode me modification du mot de passe (la 2eme) fonctionne très bien et modifie ma valeur en base .

    Je vais tenter le merge en rentrant chez moi merci

  4. #4
    Membre éclairé

    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Mai 2008
    Messages
    200
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Cameroun

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Mai 2008
    Messages : 200
    Points : 792
    Points
    792
    Par défaut
    J'ai pas lu tout ton code mais a priori la deuxième méthode ne fonctionne pas non plus car tu ne fais que changer la valeur d'un attribut sur un objet Java,
    Tu oublis un détail très important: JPA travail avec un contexte de persistance et si tu modifies une entité qui se trouve dans ce contexte (une entité managée) au moment du commit, les données en bd seront mises à jour. Hors, par défaut, la méthode find ajoute automatiquement l'entité retournée dans ce contexte d'où le résultat.
    Ingénieur Recherche et Développement en informatique à Sopra

    Page perso developpez : http://armel-ndjobo.developpez.com/
    Suivez moi sur twitter : ndjobo

  5. #5
    Membre éclairé

    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Mai 2008
    Messages
    200
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Cameroun

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Mai 2008
    Messages : 200
    Points : 792
    Points
    792
    Par défaut
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    //Récupération de l'ancien order, il n'est pas à jour, la ligne non plus.
    		Order order2 = queryName2.getSingleResult();
    quand est-ce que tu l'as mis à jour dans ton code ?
    Je n'arrive pas à mettre à jour mon orderLine
    comment sais-tu qu'il n'est pas mis à jour ?
    //on créé une nouvelle ligne
    OrderLine orderline = new OrderLine();
    orderline.setBook(book);
    orderline.setQuantity(1);
    A quel moment renseignes-tu l'identifiant de l'entité?
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    // Si je met un persist(orderline) j'ai l'erreur Caused by: javax.validation.UnexpectedTypeException: No validator could be found for type: java.lang.Integer
    essaie d'utiliser le type primitif
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    //List car getSimpleResult plante si il est vide...
    Il ne plante pas, il lève tout simplement l'exception NoResultException
    Ingénieur Recherche et Développement en informatique à Sopra

    Page perso developpez : http://armel-ndjobo.developpez.com/
    Suivez moi sur twitter : ndjobo

  6. #6
    Membre régulier
    Homme Profil pro
    Étudiant
    Inscrit en
    Janvier 2014
    Messages
    57
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Étudiant
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Janvier 2014
    Messages : 57
    Points : 93
    Points
    93
    Par défaut
    Citation Envoyé par naf87 Voir le message
    Tu oublis un détail très important: JPA travail avec un contexte de persistance et si tu modifies une entité qui se trouve dans ce contexte (une entité managée) au moment du commit, les données en bd seront mises à jour. Hors, par défaut, la méthode find ajoute automatiquement l'entité retournée dans ce contexte d'où le résultat.
    Ok merci, j'ai pas encore fait beaucoup d'applications utilisant JPA, je sais juste manipuler sans connaître tous les fondements. Juste une question (ça sera la seule pour ne pas polluer le topic) : si on n'appelle pas explicitement merge ou commit dans sa méthode, la modification opérée sur le mot de passe ne prendre pas effet immédiatement, si ? Si c'est le cas, ça pourrait parfois poser problème.

  7. #7
    Membre du Club
    Profil pro
    Inscrit en
    Janvier 2009
    Messages
    109
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2009
    Messages : 109
    Points : 46
    Points
    46
    Par défaut
    Même avec le merge ça ne fonctionne pas. Voici le process :
    J'ai un module EJB avec mes services et un module WEB avec mes bean et facelets.

    2 interrogations peuvent m'aider à comprendre :

    1 - Quand je crée un nouvel objet(entity) dans mon bean, je présume que celui-ci n'est pas persisté. Donc si on le transporte dans ma couche service, on doit le persister pour qu'il s'enregistre en base. Un simple persist(objet) devrai suffire ?

    2 - Si on récupère des objets (entity) via la base (init d'un tableau par exemple), on passe donc par notre couche service qui va récupérer en base puis faire un return de notre (nos) objets vers le bean qui, lui, va donc avoir son objet remplis et il sera affiché dans notre tableau. Cet objet ce trouvant dans notre bean, c'est par exemple :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    @postconstruct
    private void init(){
        List<Book> books = bookService.getAllBooks();
    }
    Est-ce que nos objets Book sont encore persistés dans notre bean ? Car si je clique sur une ligne de mon tableau afin de récupérer mon book dans une méthode de mon bean et que cette méthode appel la couche service via par exemple :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    private void UpBook(Book book) {
        bookService.bookUpdate(Book book)
    }
    on aura dans notre bookService la méthode :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    private void bookUpdate(Book book) {
    ????
    }
    ??? => Que mettre pour enregistrer notre modification de book en base ?
    J'ai bien essayé de mettre un em.persist(book); dans cette méthode mais j'ai ce genre de message :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    Removing a detached instance com.icl.m3.model.Book#35

  8. #8
    Membre du Club
    Profil pro
    Inscrit en
    Janvier 2009
    Messages
    109
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2009
    Messages : 109
    Points : 46
    Points
    46
    Par défaut
    Question supplémentaire :

    Si je fais :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
     
    			Author author = new Author();
    			author.setFirstName("Guillaume");
    			author.setLastName("TELL");
     
    			Book book = new Book();
    			book.setAuthor(author);
    			book.setEditor("guigui2");
    			book.setIsbn("0005");
    			book.setTitle("Moulin2");
    			book.setUnitPrice(12.0);
     
    			em.persist(book);
    Est-ce normal qu'il ne veut pas persister mon book car il me dit que je dois persister mon auteur avant ? N'y a t'il pas un moyen (via les relations Many, jointColumn etc...) de faire en sorte qu'il enregistre également les nouveaux objets liés ?

    Merci

  9. #9
    Membre confirmé Avatar de bruneltouopi
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Janvier 2010
    Messages
    308
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Ile Maurice

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Janvier 2010
    Messages : 308
    Points : 466
    Points
    466
    Par défaut
    Citation Envoyé par chido Voir le message
    Question supplémentaire :


    Est-ce normal qu'il ne veut pas persister mon book car il me dit que je dois persister mon auteur avant ? N'y a t'il pas un moyen (via les relations Many, jointColumn etc...) de faire en sorte qu'il enregistre également les nouveaux objets liés ?

    Merci
    Si une entité X est en relation avec un autre Y et que la persistance de X depend de Y alors tu devrais persister Y avant X.
    Ce sont les cas des relations @ManyToOne et l' option optional=true permet de passer cela.
    Mais Aussi il y'a la notion de CASCADE si une entité X implique la cascade de Y alors l'insertion de X déclenchera les processus de cascade de Y.
    Dans ton cas tu as certainement une relation @OneToMany de Author sur Book.
    donc Code sans cascade
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
     
    Author author = new Author();
    			author.setFirstName("Guillaume");
    			author.setLastName("TELL");
     
    			Book book = new Book();
    			book.setAuthor(author);
    			book.setEditor("guigui2");
    			book.setIsbn("0005");
    			book.setTitle("Moulin2");
    			book.setUnitPrice(12.0);
     
    em.persist(author );
    			em.persist(book);
    Avec cascade
    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
     
    Author author = new Author();
    			author.setFirstName("Guillaume");
    			author.setLastName("TELL");
     
    			Book book = new Book();
    			book.setAuthor(author);
    			book.setEditor("guigui2");
    			book.setIsbn("0005");
    			book.setTitle("Moulin2");
    			book.setUnitPrice(12.0);
     
    author.getBooks().add(book);
     
    			em.persist(author);
    [/CODE]
    Ce qui ne me tue pas me rend plus fort.

  10. #10
    Membre du Club
    Profil pro
    Inscrit en
    Janvier 2009
    Messages
    109
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2009
    Messages : 109
    Points : 46
    Points
    46
    Par défaut
    Je ne comprends pas comment faire en sorte que ça fonctionne via les relations, pourrais tu me faire un exemple stp bruneltouopi car j'ai essayé sans résultat.

    Pour le moment je fais comme tu as dit, je persist les entités l'une après l'autre et tout fonctionne mais ce n'est pas très jolie .

    naf87 => Pour l'erreur que j'avais :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    No validator could be found for type: java.lang.Integer
    J'ai juste enlevé les annotations @NotNull/Empty/blank d'une variable (j'ai fais au compte goutte) pour que ça fonctionne.... aucune explication sauf peut être que ces annotations ne fonctionnent que sur des String.

    -Dici- => A mon avis ce n'est pas une bonne méthode que j'utilise, je pense que la structure de mon projet y ai aussi pour quelque chose. La preuve, mes entity manager ne fonctionne pas avec mes JUnits alors qu'ils sont instancié exactement pareil dans mes tests unitaires que dans ma couche service. Par contre en bidouillant j'ai réussi à ce qu'il ne soit pas à null mais l'accès à la base ne fonctionne pas.. Bref ceci est une autre histoire, je perdrais 5 points sur ma notations et de toute manière personne de mon entourage n'as réussi JUNIT ^^

  11. #11
    Membre éprouvé
    Avatar de Cafeinoman
    Homme Profil pro
    Couteau suisse d'une PME
    Inscrit en
    Octobre 2012
    Messages
    628
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 37
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Couteau suisse d'une PME

    Informations forums :
    Inscription : Octobre 2012
    Messages : 628
    Points : 1 256
    Points
    1 256
    Par défaut
    Salut Chido,

    pour (essayer) de répondre à tes questions :

    _oui, quand tu créé un nouvel objet, un simple persist(object) est suffisant. Je dirais même, pour en avoir fait l'expérience il y a peu, que c'est la première chose à faire un fois la construction basique (toutes les colonnes not null) effectué. Ensuite, mais j'ignore si la pratique est bonne, un persist(merge(object)) après chaque modification pour être certain qu'elle est bien prise en compte.

    _ Pour les liens entre vue, service et dao, ton bean de vue appel ta couche service, qui elle même appel le dao. Autrement dit, au moment d'un appel, ton dao récupère une entité en base, la met dans le persistence context (avec un find() en général), puis la couche service récupère ce bean, y applique éventuellement des traitements métiers, et refile le bean à la vue pour affichage. Mais la couche de service ne voit pas l'EntityManager en lui même, elle ne voit que l'interface de dao.

    _Si tu ne fait pas de cascade, c'est normal. Avec un code de ce genre :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    public class Author {
    ...
    @OneToMany(mappedBy="auteur", cascade=CascadeType.ALL, orphanRemoval = true)
    private Set<Book> livres = new HashSet<Book>();
    et

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    public class Book {
    ...
    @ManyToOne(cascade={CascadeType.Merge,CascadeType.PERSIST,CascadeType.REFRESH})
    private Author auteur;
    devrait te permettre de tout persister en n'en persistant qu'un des deux. Quant au remove, il supprimera tous les livres si tu enlève l'auteur, et l'auteur s'il n'y a plus de livre associé.
    «Dieu ne joue pas aux dés.» - Albert Einstein. Et pan! 30 ans de retard dans la théorie quantique!
    «Tout n'est pas politique, mais la politique s'intéresse à tout.» - Nicolas Machiavel. Et surtout à ceux qui ne s'y intéressent pas.

  12. #12
    Membre du Club
    Profil pro
    Inscrit en
    Janvier 2009
    Messages
    109
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2009
    Messages : 109
    Points : 46
    Points
    46
    Par défaut
    Avec les explications sur les cascades j'ai donc mis en application ces méthodes sur toutes mes entités. J'ai maintenant des entités qui se mettent à jours en base via MERGE ou PERSIST sans devoir persister les objets liés. J'ai pu enlever pas mal de code "degeu" qui me servait à détourner le problème. Un grand merci !

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

Discussions similaires

  1. Problème de compréhension pour <<interface>>
    Par tnarol dans le forum UML
    Réponses: 7
    Dernier message: 07/02/2007, 20h07

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