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

JSF Java Discussion :

Créer et persister une entitée avec relation @ManyToOne


Sujet :

JSF Java

  1. #1
    Membre habitué Avatar de touftouf57
    Profil pro
    Développeur .NET
    Inscrit en
    Décembre 2007
    Messages
    362
    Détails du profil
    Informations personnelles :
    Âge : 46
    Localisation : France, Moselle (Lorraine)

    Informations professionnelles :
    Activité : Développeur .NET
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Décembre 2007
    Messages : 362
    Points : 174
    Points
    174
    Par défaut Créer et persister une entitée avec relation @ManyToOne
    Bonjour,

    Je cherche surtout une bonne pratique concernant la création + persistence d'une entité.

    Voila, j'ai une classe @Entity Affaire avec ses propriétés et ceci:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    @JoinColumn(name = "IDCONTACT", referencedColumnName = "IDCONTACT")
        @ManyToOne
        private Contact contact;
        @JoinColumn(name = "IDCLIENT", referencedColumnName = "IDCLIENT", nullable=false)
        @ManyToOne
        private Client client;
        @JoinColumn(name = "IDCHARGEAFFAIRE", referencedColumnName = "IDCHARGEAFFAIRE")
        @ManyToOne
        private ChargeAffaire chargeAffaire;
    Bien entendu les classes Client, ChargeAffaire et Contact font référence à Affaire

    Maintenant dans la page JSF pour la création d'une affaire j'ai des h:selectOneListbox qui obtiennent leurs f:selectItems de différents managed bean (ClientCtrlBean, ChargeAffaireCtrlBean).

    J'espère être clair jusque là.

    Donc sur ma page JSF lorsque je selectionne une valeur dans un de mes combobox, il me renvoie un (int, long,...), et pas l'objet en question.

    Ce qui fait que dans mon managed-bean AffaireCtrlBean, je dois faire des findBy(idClient) pour re-récupérer le client sélectionné.
    Je trouve cela un peu tordu, et peu performant.
    N'est-il pas possible de récupérer LE client selectionné directement du style:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    <h:outputText value="#{bundle.nomClient} :"/>
    <h:selectOneListbox value="#{affaireCtrlBean.affaire.client}" size="1">
            <f:selectItems value="#{clientCtrlBean.selectItemClientsAll}" />
    </h:selectOneListbox>
    Comment faites-vous pour améliorer ce processus?

    Merci, et j'espère avoir été assez clair.

  2. #2
    Rédacteur

    Profil pro
    Inscrit en
    Juin 2003
    Messages
    4 184
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2003
    Messages : 4 184
    Points : 5 059
    Points
    5 059
    Par défaut
    Si tu veux récupérer l'objet, tu dois utiliser un converter;

    tu trouvera dans la faq des exemples.

  3. #3
    Membre du Club
    Inscrit en
    Décembre 2009
    Messages
    68
    Détails du profil
    Informations forums :
    Inscription : Décembre 2009
    Messages : 68
    Points : 59
    Points
    59
    Par défaut
    tu veux diminuer les allés retour à la base de données pour un souci de performance, tu peux récupérer la liste de tous les clients, ensuite quand tu sélectionnes un client tu boucle sur ta liste pour le récupérer. Tu gagnes en performances.

  4. #4
    Membre habitué Avatar de touftouf57
    Profil pro
    Développeur .NET
    Inscrit en
    Décembre 2007
    Messages
    362
    Détails du profil
    Informations personnelles :
    Âge : 46
    Localisation : France, Moselle (Lorraine)

    Informations professionnelles :
    Activité : Développeur .NET
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Décembre 2007
    Messages : 362
    Points : 174
    Points
    174
    Par défaut
    Merci pour les conseils.

    J'ai donc essayé de faire des converters mais je me récupère le message "Erreur de validation: Valeur not valid."

    A ce que j'ai lu c'est que le type envoyé ne correspond pas au type attendu pourtant je l'ai défini dans le face-config comme ceci:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    <converter>
           <converter-for-class>com.enregistrementAffaires.entites.Client</converter-for-class>
           <converter-class>com.enregistrementAffaires.jsfConverter.ClientConverter</converter-class>
       </converter>
    la méthode getAsObject est bien effectuée puisque j'atteinds le return c avec la valeur sélectionnée:
    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
     
     public Object getAsObject(FacesContext context, UIComponent component, String value) {
     
            if (value == null || value.length() == 0) {
                return null;
            }
            Integer id = new Integer(value);
            ClientControleur clientController = (ClientControleur) context.getApplication().getELResolver().getValue(context.getELContext(), null, "clientMB");
            List<Client> clients= clientController.getClients();
            for(Client c:clients){
                if(c.getId().equals(id)){
                    return c;
                }
            }
            return null; //TODO: lève une exception plutôt
        }
    Voila comment je l'appelle depuis ma jsp
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    <h:outputText value="#{bundle.nomClient} :"/>
    <h:selectOneListbox value="#{affaireMB.aff.client}" size="1">
           <f:selectItems value="#{clientMB.selectItemClientsAll}"/>
     </h:selectOneListbox>
    Je ne saisis pas pourquoi j'obtiens cette erreur vu que le converter est appliquable à la classe Client et renvoie une instance de Client. Cela serait-il dû au selectItems??

    Encore merci pour le liens vers la FAQ. Quelqu'un peut m'éclairer la dessus?

  5. #5
    Membre régulier
    Profil pro
    Inscrit en
    Mars 2007
    Messages
    191
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2007
    Messages : 191
    Points : 118
    Points
    118
    Par défaut
    Tu veux un id dans ton converter donc tu dois avoir :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    <h:selectOneListbox value="#{affaireMB.aff.client.id}" size="1">
           <f:selectItems value="#{clientMB.selectItemClientsAll}"/>
    </h:selectOneListbox>

  6. #6
    Rédacteur

    Profil pro
    Inscrit en
    Juin 2003
    Messages
    4 184
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2003
    Messages : 4 184
    Points : 5 059
    Points
    5 059
    Par défaut
    dans getAsObject, la valeur est l'objet Client pas seulement l'id. tu dois passer une valeur de type Client à ton selectOneMenu et dans les selectItems;
    et N'oublie pas d'implémenter getAsString.

    Mais tu peux le faire également lors de la sélection, parcourir la liste et trouver l'objet sélectionné faire un appel à la base.

  7. #7
    Membre habitué Avatar de touftouf57
    Profil pro
    Développeur .NET
    Inscrit en
    Décembre 2007
    Messages
    362
    Détails du profil
    Informations personnelles :
    Âge : 46
    Localisation : France, Moselle (Lorraine)

    Informations professionnelles :
    Activité : Développeur .NET
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Décembre 2007
    Messages : 362
    Points : 174
    Points
    174
    Par défaut
    Et bien cela fait toute la journée que j'essaye d'implémenter getAsString et getAsObject, et qu'a chaque tentative cela ne fonctionne pas (généralement une erreur de conversion).
    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
     
    public class ClientConverter implements Converter {
     
        public Object getAsObject(FacesContext context, UIComponent component, String value) {
     
            if (value == null || value.length() == 0) {
                return null;  //TODO: lève une exception plutôt
            }
            Integer id = new Integer(value);
            ClientControleur clientController = (ClientControleur) context.getApplication().getELResolver().getValue(context.getELContext(), null, "clientMB");
            List<Client> clients= clientController.getClients();
            for(Client c:clients){
                if(c.getId().intValue()==id.intValue()){
                    System.out.println(c.getId().intValue() + " - "+ id.intValue());
                    return c;
                }
            }
            return null; //TODO: lève une exception plutôt
        }
     
     
        public String getAsString(FacesContext context, UIComponent component, Object value) {
            return ((Client)value).toString();
        }
     
    }
    Donc si j'ai
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    <h:selectOneListbox value="#{affaireMB.aff.client}" size="1" converter="clientConverter">
           <f:selectItems value="#{clientMB.selectItemClientsAll}"/>
     </h:selectOneListbox>
    clientMB.selectItemClientsAll doit me retourner une liste(List, Map ou tableau) de SelectItem obligatoirement, oui?

    J'ai un autre souci: avec cette configuration, lors de l'activation de la page la combobox n'affiche pas la valeur contenu dans aff.client. Je suppose que cela proviens du getAsString.

    Mais que doit me retourner getAsObject dans mon cas? un SelectItem<idClient,Client> ou un Client?

    Quelqu'un pourrait-il me présenter une solution, parce que la je patauge sérieusement.
    Merci d'avance, pour vos conseils

  8. #8
    Membre habitué Avatar de touftouf57
    Profil pro
    Développeur .NET
    Inscrit en
    Décembre 2007
    Messages
    362
    Détails du profil
    Informations personnelles :
    Âge : 46
    Localisation : France, Moselle (Lorraine)

    Informations professionnelles :
    Activité : Développeur .NET
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Décembre 2007
    Messages : 362
    Points : 174
    Points
    174
    Par défaut
    bon j'ai continué mes investigations, sans succès.

    J'ai voulu faire un getById(idClient) de mon EJB ClientFacade et je me retrouve confronté à un autre souci, on ne peut pas injecter d'EJB (annotation @EJB) ailleurs que dans un managedBean.

    je voudrais donc faire référence à ce stateless:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    @Stateless(name = "ClientSB", mappedName = "ejb/stateless/Client")
    public class ClientFacade extends Facade implements ClientFacadeLocal, ClientFacadeRemote {...
    J'ai donc parcouru le web et développez.com, et j'ai trouvé ceci:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    clientBean =  (ClientFacade) facesContext.getApplication().getELResolver().getValue(facesContext.getELContext(), null, "ejb/stateless/Client");
    mais une fois cette instruction passé clientBean est null. Je comprend bien que c'est un stateless, mais pourquoi je n'arrive pas à pointer dessus. Si j'utilise une autre technique, je n'ai plus d'entité manager dans ce bean.

    A l'aide, 3 jours pour implémenter un Converter. Je me sens tout pourri.

  9. #9
    Membre habitué Avatar de touftouf57
    Profil pro
    Développeur .NET
    Inscrit en
    Décembre 2007
    Messages
    362
    Détails du profil
    Informations personnelles :
    Âge : 46
    Localisation : France, Moselle (Lorraine)

    Informations professionnelles :
    Activité : Développeur .NET
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Décembre 2007
    Messages : 362
    Points : 174
    Points
    174
    Par défaut
    Et bien je ne suis toujours pas arrivé à mes fins.

    Pourtant en parcourant l'arborescence de FaceContext.application.application....EnterpriseBeans (je n'ai plus le chemin en tete) je vois bien l'EJB que je cherche à référencer. Mais je n'arrive pas à coder sa référence.

    Maintenant est-ce la bonne technique pour arriver à mes fins? Est-ce que "ClientSB" est correct? par quelle valeur puis accéder à mon EJB? (name = "ClientSB", mappedName = "ejb/stateless/Client")?

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    facesContext.getApplication().getELResolver().getValue(facesContext.getELContext(), null, "ClientSB");
    J'ai aussi vu que l'on pouvait l'atteindre par initialContext.lookup(""). Mais la question reste la meme? quelle valeur faut-il rechercher?
    J'ai vu un sur certain site http://java.sun.com/javaee/6/docs/tu...doc/gipjf.htmlqu'il fallait spécifié un chemin en fonction de si l'on se trouve hors ou a l'intérieur du conteneur ("java:app/..." ; "java:module/...")

    Mais ce que je n'ai pas compris c'est s'il fallait spécifier le chemin complet (nom du module + package + classe)

    Du coup je me pose une question, faut-il passer par le managedBean pour accéder à l'EJB???

    Pour tout vous dire je me sens vraiment perdu dans tout ça. Un coup de main serait très appréciable, trois nuit la dessus je commence à me décourager

  10. #10
    Membre habitué Avatar de touftouf57
    Profil pro
    Développeur .NET
    Inscrit en
    Décembre 2007
    Messages
    362
    Détails du profil
    Informations personnelles :
    Âge : 46
    Localisation : France, Moselle (Lorraine)

    Informations professionnelles :
    Activité : Développeur .NET
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Décembre 2007
    Messages : 362
    Points : 174
    Points
    174
    Par défaut
    Bon je crois avoir saisi.
    Donc pour ce code là:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    <h:selectOneListbox value="#{affaireMB.aff.client}" size="1" converter="clientConverter">
           <f:selectItems value="#{clientMB.selectItemClientsAll}"/>
     </h:selectOneListbox>
    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
     
    @FacesConverter(forClass = Client.class)
    public static class ClientControleurConverter implements Converter {
     
            public Object getAsObject(FacesContext facesContext, UIComponent component, String value) {
                if (value == null || value.length() == 0) {
                    return null;
                }
                ClientControleur controller = (ClientControleur)facesContext.getApplication().getELResolver().
                        getValue(facesContext.getELContext(), null, "clientMB");
     
                return controller.clientBean.findById(Integer.parseInt(value));
     
            }
     
     
            public String getAsString(FacesContext facesContext, UIComponent component, Object object) {
                if (object == null) {
                    return null;
                }
                if (object instanceof Client) {
                    Client o = (Client) object;
                    return o.toString();
                } else {
                    throw new IllegalArgumentException("object " + object + " is of type " + object.getClass().getName() + "; expected type: "+Client.class.getName());
                }
            }
    J'ai mis la classe Converter en sous-classe du controleur. De cette façon je récupère une référence sur le managed-bean via le FacesContext, mais je n'ai pas besoin de générer le getter/setter de l'EJB. Car la sous-classe peut accéder aux propriétés privées de sa classe "parente". [je ne dit pas super-classe ou classe mère puisqu'il n'y a pas de notions d'héritage]

    La méthode getAsString reverra un "code" qui sera la "value" transmise à la méthode getAsObject.
    Et getAsObject, fait un traitement pour récupérer l'objet correspondant au "code" et le renverra. L'objet récupéré doit être du type de la propriété du Managed Bean, dans mon cas Client.
    Exact?

    Maintenant, pour être bien sur d'avoir saisi j'aurais voulu faire ceci:
    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
     
    public class LoginConverter implements Converter {
     
            public Object getAsObject(FacesContext facesContext, UIComponent component, String value) {
                if (value == null || value.length() == 0) {
                    return null;
                }
                Integer i= new Integer(value);
                return i;
            }
     
            public String getAsString(FacesContext context, UIComponent component, Object object) {
                if (object == null) {
                    return null;
                }
                ChargeAffaire c = (ChargeAffaire) object;
                return c.getId().toString();
            }
        }
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    <h:selectOneMenu id="lstbChargeAffaire" value="#{compteMB.idChargeAffaire}" converter="loginConverter">
                                            <f:selectItems value="#{chargeAffaireMB.selectItemChargeAffaireAll}"/>
                                        </h:selectOneMenu>
    avec idChargeAffaire de type Integer et selectItemChargeAffaireAll renvoir un tableau de SelectItem<ChargeAffaire, ChargeAffaire.toString()>

    Je cherche juste à récupérer l'identifiant du charge d'affaire, que l'utilisateur aura choisi dans une liste de charge d'affaire. Puis stocker cet identifiant dans un integer de mon managed-bean.

    Mais la je me reprend une erreur de conversion. Pourtant idChargeAffaire est bien de type Integer et getAsObject renvoie un Integer.

    Quelqu'un voit-il ce que j'ai pas compris, ou mal interprété?

    merci

  11. #11
    Membre du Club
    Inscrit en
    Décembre 2009
    Messages
    68
    Détails du profil
    Informations forums :
    Inscription : Décembre 2009
    Messages : 68
    Points : 59
    Points
    59
    Par défaut
    il suffit que la valeur de ton selectItem soit l'id. Pour le label tu peux mettre ce que tu veux.
    C'est à dire au lieu de
    Code java : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    SelectItem(ChargeAffaire, ChargeAffaire.toString()) tu mets
    SelectItem(ChargeAffaire.getId(), ChargeAffaire.toString())

  12. #12
    Membre habitué Avatar de touftouf57
    Profil pro
    Développeur .NET
    Inscrit en
    Décembre 2007
    Messages
    362
    Détails du profil
    Informations personnelles :
    Âge : 46
    Localisation : France, Moselle (Lorraine)

    Informations professionnelles :
    Activité : Développeur .NET
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Décembre 2007
    Messages : 362
    Points : 174
    Points
    174
    Par défaut
    Ok, mais je ne veux pas créer plusieurs méthodes pour peupler mes selectOneListBox. Une fois avec des SelectItem<ChargeAffaire,ChargeAffaire.toString()> et une autre fois avec SelectItem<ChargeAffaire.getId(),ChargeAffaire.toString()>

    Je suppose qu'il est possible, mais je n'ai pas trouvé l'astuce, de convertir, grace à un Converter, un SelectItem<ChargeAffaire, ChargeAffaire.toString()> en un integer, pour stocker chargeAffaire.getId() dans #{affaireMB.idChargeAffaireLogin}

    A moins que je me plante complètement.

    Ceci est-il possible?

  13. #13
    Membre du Club
    Inscrit en
    Décembre 2009
    Messages
    68
    Détails du profil
    Informations forums :
    Inscription : Décembre 2009
    Messages : 68
    Points : 59
    Points
    59
    Par défaut
    Code xml : Sélectionner tout - Visualiser dans une fenêtre à part
    value="#{compteMB.idChargeAffaire}"
    c'est l'id de ton objet?? Si c'est le cas t'as plus besoin de converter et il suffit que la liste de selectItem au lieu de recuperer tout l'objet comme value récupère l'objet.getId() et puis suivant l'id de ton objet tu recupere tout l'objet. j'espère que tu m'as bien compris

Discussions similaires

  1. Persistence d'une classe avec mapping ManyToOne
    Par yo_haha dans le forum JPA
    Réponses: 1
    Dernier message: 21/11/2013, 14h13
  2. Réponses: 1
    Dernier message: 22/05/2013, 15h01
  3. [2.x] [Formulaire] Créer une entité avec une relation ManyToMany
    Par SalutAVous dans le forum Symfony
    Réponses: 3
    Dernier message: 30/10/2012, 22h13
  4. Une entité avec plusieurs relations oneToOne
    Par ray-k dans le forum Doctrine2
    Réponses: 5
    Dernier message: 03/08/2012, 15h55
  5. [Hibernate] Faire une requête avec relation NN
    Par n@n¤u dans le forum Hibernate
    Réponses: 20
    Dernier message: 25/07/2006, 10h39

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