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

Hibernate Java Discussion :

Problème de jointure/requête [HQL]


Sujet :

Hibernate Java

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre averti
    Inscrit en
    Avril 2012
    Messages
    21
    Détails du profil
    Informations forums :
    Inscription : Avril 2012
    Messages : 21
    Par défaut Problème de jointure/requête
    Bonjour,

    J'ai un problème qui m'arrache les cheveux, n'étant pas un expert en J2EE et encore moins avec Jboss, hibernate and Co. je désespère.

    Pour vous faire le contexte, c'est client, qui possède des comptes et qui doit se connecté, donc je récupère leur numéro de compte et leur code secret. Le numéro de compte est dans l'entity Compte et le code secret dans l'entity Client.

    Maintenant voici les entity :
    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
    package P.Client;
     
    import java.io.Serializable;
    import java.util.Collection;
    import javax.persistence.*;
    import P.Compte.Compte;
     
    @Entity
    public class Client implements Serializable {
     
    	@Id
    	@GeneratedValue (strategy=GenerationType.AUTO)
    	private int numclient;
     
    	private String prenom;
    	private String nom;
    	private String codesecret;
     
    	@OneToMany(cascade={CascadeType.REMOVE, CascadeType.PERSIST}, mappedBy="client") 
    	private Collection<Compte> compte;
     
    	public int getNumclient() {
    		return numclient;
    	}
     
    	public void setNumclient(int numclient) {
    		this.numclient = numclient;
    	}
     
    	public String getPrenom() {
    		return prenom;
    	}
     
    	public void setPrenom(String prenom) {
    		this.prenom = prenom;
    	}
     
    	public String getNom() {
    		return nom;
    	}
     
    	public void setNom(String nom) {
    		this.nom = nom;
    	}
     
    	public String getCodesecret() {
    		return codesecret;
    	}
     
    	public void setCodesecret(String codesecret) {
    		this.codesecret = codesecret;
    	}
     
    	public Collection<Compte> getCompte() {
    		return compte;
    	}
     
    	public void setCompte(Collection<Compte> compte) {
    		this.compte = compte;
    	}
     
    }
    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
    64
    65
    66
    67
    68
    69
    package P.Compte;
     
    import java.io.Serializable;
    import java.util.Collection;
    import java.util.Date;
    import javax.persistence.*;
    import P.Client.Client;
    import P.Operation.Operation;
     
    @Entity
    public class Compte implements Serializable {
     
    	@Id
    	@GeneratedValue (strategy=GenerationType.AUTO)
    	private int numcompte;
     
    	private int solde;
     
    	@Temporal(TemporalType.DATE)
    	private Date date;
     
    	@ManyToOne
    	@JoinColumn(name="numclient") 
    	private Client client;
     
    	@OneToMany(cascade={CascadeType.REMOVE, CascadeType.PERSIST}, mappedBy="compte") 
    	private Collection<Operation> operation;
     
    	public int getNumcompte() {
    		return numcompte;
    	}
     
    	public void setNumcompte(int numcompte) {
    		this.numcompte = numcompte;
    	}
     
    	public int getSolde() {
    		return solde;
    	}
     
    	public void setSolde(int solde) {
    		this.solde = solde;
    	}
     
    	public Date getDate() {
    		return date;
    	}
     
    	public void setDate(Date date) {
    		this.date = date;
    	}
     
    	public Client getClient() {
    		return client;
    	}
     
    	public void setClient(Client client) {
    		this.client = client;
    	}
     
    	public Collection<Operation> getOperation() {
    		return operation;
    	}
     
    	public void setOperation(Collection<Operation> operation) {
    		this.operation = operation;
    	}
     
    }
    Voici la requête : (les requêtes en commentaire fonctionne ...)

    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
    public Boolean connexion(String numcompte, String codesecret){
     
        	Boolean result = false;
     
        	Query q = em.createQuery("select numclient from P.Compte.Compte as c, P.Client.Client as cl where cl.numclient = c.numclient and c.numcompte = :numcompte and cl.codesecret = :codesecret");
        	q.setParameter("numcompte", numcompte);
        	q.setParameter("codesecret", codesecret);
     
        	/*Query q = em.createQuery("from Compte where Numcompte = :numcompte");
            q.setParameter("numcompte", numcompte);
        	
            Query m = em.createQuery("from Client where Numclient = :idclient and Codesecret = :codesecret");
            m.setParameter("codesecret", codesecret);
            m.setParameter("idclient", 1);
            
            System.out.println(m.getResultList());*/
     
        	if(q.getResultList().size() == 1)
        		result = true;
     
        	return result;
        }
    Et voici le message d'erreur :

    23:04:01,442 ERROR [org.jboss.ejb3.invocation] (http-localhost-127.0.0.1-8080-1) JBAS014134: EJB Invocation failed on component CompteManager for method public abstract java.lang.Boolean P.Compte.CompteManagerRemote.connexion(java.lang.String,java.lang.String): javax.ejb.EJBException: java.lang.IllegalArgumentException: org.hibernate.QueryException: could not resolve property: numclient of: P.Compte.Compte [select numclient from P.Compte.Compte as c, P.Client.Client as cl where cl.numclient = c.numclient and c.numcompte = :numcompte and cl.codesecret = :codesecret]

    Caused by: java.lang.IllegalArgumentException: org.hibernate.QueryException: could not resolve property: numclient of: P.Compte.Compte [select numclient from P.Compte.Compte as c, P.Client.Client as cl where cl.numclient = c.numclient and c.numcompte = :numcompte and cl.codesecret = :codesecret]

    Caused by: org.hibernate.QueryException: could not resolve property: numclient of: P.Compte.Compte [select numclient from P.Compte.Compte as c, P.Client.Client as cl where cl.numclient = c.numclient and c.numcompte = :numcompte and cl.codesecret = :codesecret]

    23:04:01,474 ERROR [org.apache.catalina.core.ContainerBase.[jboss.web].[default-host].[/ProjetDistributeurWeb].[ServletConnexion]] (http-localhost-127.0.0.1-8080-1) "Servlet.service()" pour la servlet ServletConnexion a généré une exception: javax.ejb.EJBException: java.lang.IllegalArgumentException: org.hibernate.QueryException: could not resolve property: numclient of: P.Compte.Compte [select numclient from P.Compte.Compte as c, P.Client.Client as cl where cl.numclient = c.numclient and c.numcompte = :numcompte and cl.codesecret = :codesecret]

    Caused by: java.lang.IllegalArgumentException: org.hibernate.QueryException: could not resolve property: numclient of: P.Compte.Compte [select numclient from P.Compte.Compte as c, P.Client.Client as cl where cl.numclient = c.numclient and c.numcompte = :numcompte and cl.codesecret = :codesecret]

    Caused by: org.hibernate.QueryException: could not resolve property: numclient of: P.Compte.Compte [select numclient from P.Compte.Compte as c, P.Client.Client as cl where cl.numclient = c.numclient and c.numcompte = :numcompte and cl.codesecret = :codesecret]
    Auriez vous une idée ? Si vous avez besoin des classes Remote ou que sais-je, je ferais un copier-coller avec plaisir

  2. #2
    Membre chevronné
    Profil pro
    Inscrit en
    Mai 2008
    Messages
    394
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2008
    Messages : 394
    Par défaut
    Bonjour,

    Tu peux essayer de préfixer "numclient" par "cl." : "select cl.numclient from...", mais je ne suis pas sûr que ça règle le problème.

    Sinon quelque chose du style doit marcher je pense :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    Query q = em.createQuery("from Compte as compte JOIN compte.client as client where compte.numcompte = :numcompte and client.codesecret = :codesecret")
    Romain.

  3. #3
    Membre averti
    Inscrit en
    Avril 2012
    Messages
    21
    Détails du profil
    Informations forums :
    Inscription : Avril 2012
    Messages : 21
    Par défaut
    J'ai déjà essayer de fixer le numclient par c.numclient ou cl.numclient et cela ne change rien

    Sans le select je peux quand même récupérer tous mes champs ?

  4. #4
    Membre Expert
    Profil pro
    Inscrit en
    Août 2006
    Messages
    3 276
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2006
    Messages : 3 276
    Par défaut
    C'est un peu logique, tu n'as pas de propriété numClient dans ta classe compte.
    Tu dois y accéder par c.client.numClient.

    Autre chose, les noms de package s'écrivent en minuscules, car là, c'est illisible.

    Essaie un quelque chose de ce genre :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    select c
    from Compte c
    where c.numcompte = :numcompte and c.client.codesecret = :codesecret

  5. #5
    Membre chevronné
    Profil pro
    Inscrit en
    Mai 2008
    Messages
    394
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2008
    Messages : 394
    Par défaut
    Si tu veux que le contenu de la classe Client soit remonté aussi, il faut ajouter "fetch" :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    Query q = em.createQuery("from Compte as compte JOIN FETCH compte.client as client where compte.numcompte = :numcompte and client.codesecret = :codesecret")
    Cependant la seule chose que tu fais avec le retour de ta requête c'est :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    if(q.getResultList().size() == 1)
        		result = true;
    Donc je ne vois pas en quoi tu as besoin de remonter les informations de la table client...

    Je t'invite à lire la doc sur les requêtes HQL : http://docs.jboss.org/hibernate/orm/.../queryhql.html Elle est très bien faite.

    Romain.

  6. #6
    Membre averti
    Inscrit en
    Avril 2012
    Messages
    21
    Détails du profil
    Informations forums :
    Inscription : Avril 2012
    Messages : 21
    Par défaut
    Bonjour,

    Déjà merci pour votre intervention, n'étant actuellement pas devant mon application (pas avant se soir), j'aurais juste des questions théorique parce que je dois dire que pour vous sa semble logique, mais moi le HQL ... pas du tout.

    C'est un peu logique, tu n'as pas de propriété numClient dans ta classe compte.
    Aurais-je du faire autrement mes entity ? Parce que je croyais qu'en déclarant un objet en clé étrangère, il récupérerait le Client associé au Compte avec ses attributs etc.

    Je testerais en rentrant se soir ta requête fr1man, je te redis sa rapidement.

    Si tu veux que le contenu de la classe Client soit remonté aussi, il faut ajouter "fetch"
    Toujours de mémoire car étant au boulot, je crois avoir déjà essayer dans la requête car j'avais essayer au départ les INNER JOIN moderne, puis je suis revenu à l'ancêtre avec les WHERE, mais entre-temps j'ai été chercher sur internet de la doc, après j'ai peut être raté la syntaxe, je réessayerais également.

    Oui actuellement je n'ai pas besoin de remonter les infos client car j’essaie de faire une simple confirmation d'authentification, mais je vais en avoir besoin pour les infos compte quand je vais devoir me pencher sur les Sessions. D'ailleurs il va falloir que je trouve comment récupérer les données du getResultList, certainement avec une boucle.

    Pour la doc, c'est bien celle-ci que j'ai consulter, mais je n'ai pas du savoir l'exploiter correctement, en plus elle passe du français vers l'anglais, ce qui me bloque réellement dans la compréhension s'est l'association Entity/BDD pour comprendre la syntaxe du HQL.

  7. #7
    Membre chevronné
    Profil pro
    Inscrit en
    Mai 2008
    Messages
    394
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2008
    Messages : 394
    Par défaut
    Citation Envoyé par V1p34r Voir le message
    Aurais-je du faire autrement mes entity ? Parce que je croyais qu'en déclarant un objet en clé étrangère, il récupérerait le Client associé au Compte avec ses attributs etc.
    Il me semble que par défaut quand tu as une relation 1..1, Hibernate ramène automatiquement les données de la table étrangère (secondaire). (c'est ce qu'on appelle le eager loading)

    Sur une relation "1..n" Hibernate ne ramènera pas le contenu de la liste par défaut. ça ne sera que lorsque dans ton code java tu accèderas à cette liste qu'il effectuera la requête (c'est ce qu'on appelle le lazy loading).

    Ton Compte étant relié à un Client si tu fait un select sur client tu dois obtenir les données de la classe Compte aussi. En revanche un Client est relié à plusieurs Compte, si tu fais un select sur Client les données de compte ne seront pas automatiquement remontées, il faut alors faire un "join fetch" explicite dans ta requête HQL, ou ajouter une annotation "@OneToMany(fetch=FetchType.EAGER)" sur ta liste.

    Mais j'ai tendance à écrire un fetch tout le temps quand je veux récupérer des données d'une table jointe, comme ça tu ne te pose pas de question sur le paramétrage par défaut d'Hibernate (qui en plus pourrait changer d'une version à l'autre).

    Romain.

  8. #8
    Membre Expert
    Profil pro
    Inscrit en
    Août 2006
    Messages
    3 276
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2006
    Messages : 3 276
    Par défaut
    Aurais-je du faire autrement mes entity ? Parce que je croyais qu'en déclarant un objet en clé étrangère, il récupérerait le Client associé au Compte avec ses attributs etc.
    Non ton mapping est bon, mais tu n'as pas d'attributs numclient directement dans ta classe compte.
    Donc quand tu écris compte.numclient, Hibernate cherche un attribut numclient qu'il ne trouve pas.
    Il faut que tu écrives, compte.client.numclient.

    Prends l'habitude d'écrire tes requetes (meme en SQL d'ailleurs) avec la syntaxe join, c'est bien plus lisible et séparé des filtres réalisés par le where)

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

Discussions similaires

  1. Réponses: 6
    Dernier message: 01/12/2007, 22h28
  2. Réponses: 24
    Dernier message: 24/07/2007, 17h48
  3. [MySQL] problème dans ma requête de jointure
    Par kawther dans le forum PHP & Base de données
    Réponses: 2
    Dernier message: 16/04/2007, 22h50
  4. [Requête] Problème de jointure
    Par Oilcout dans le forum Requêtes et SQL.
    Réponses: 4
    Dernier message: 27/03/2007, 16h54
  5. [Requêtes SQL] Problème de jointure ?
    Par soso78 dans le forum Requêtes et SQL.
    Réponses: 6
    Dernier message: 18/12/2006, 15h37

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