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 :

Hibernate : Lazy / eager : failed to lazily initialize a collection of role:


Sujet :

Hibernate Java

  1. #1
    Nouveau membre du Club
    Inscrit en
    Août 2011
    Messages
    109
    Détails du profil
    Informations forums :
    Inscription : Août 2011
    Messages : 109
    Points : 32
    Points
    32
    Par défaut Hibernate : Lazy / eager : failed to lazily initialize a collection of role:
    Bonjour.

    J'ai un probleme simple avec hibernate et struts 2.

    J'ai un objet Tarif qui contient une liste de tarifValeur :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    <class name="cpte.hibernate.CpteTarif" table="CPTE_TARIF">
            ....
            <set name="cpteTarifvaleurs" table="CPTE_TARIFVALEUR" inverse="true" lazy="true" cascade="all" fetch="select">
                <key>
                    <column name="TAR_ID" precision="22" scale="0" not-null="true" />
                </key>
                <one-to-many class="cpte.hibernate.CpteTarifvaleur" />
            </set>
        </class>
    Sur la page jsp qui affiche la liste des tarifs, je peux cliquer sur un lien qui affiche le détail de celui-ci (dont ces valeurs).

    Dans struts, je fais donc :
    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 String loadTarif() throws Exception
        {
    		HttpServletRequest request = (HttpServletRequest) ActionContext.getContext().get(ServletActionContext.HTTP_REQUEST);
    		long tarifId = Long.parseLong(request.getParameter("tarif.tarId"));
    		tarif = CpteTarifDao.getInstance().get(tarifId); 
    		if(tarif==null)
    		{
    			addActionError(getText("error.baseDeDonnees"));
    			return INPUT;
    		}
     
    		HibernateUtil.closeSession();
    		return SUCCESS;
        }
    puis dans la jsp qui suis, j'ai le code suivant :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
     
    <c:forEach var="tarifValeur"
    					items="${tarif.cpteTarifvaleurs}"
    					varStatus="status">
    					<tr>
    						<td>${tarifValeur.valId}</td>
    						<td><fmt:formatDate  pattern="dd/MM/yyyy"  value="${tarifValeur.valDateEffet}"/></td>
    						<td><fmt:formatDate  pattern="dd/MM/yyyy"  value="${tarifValeur.valDateFin}"/></td>
    						<td><fmt:formatNumber value="${tarifValeur.valMontant}" type="currency" currencySymbol="&euro;"/></td>
    					</tr>
     
    				</c:forEach>
    Ce code affiche l'erreur : org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: cpte.hibernate.CpteTarif.cpteTarifvaleurs, could not initialize proxy - no Session
    car la session est close (je la ferme dans loadTarif()).
    Bien sur, si je ne ferme pas la session préalablement, ca fonctionne correctement, mais j'avais vu que ne pas fermer une session pouvait poser des problèmes lors d'update dans un précédent message sur le forum.

    Doit-on mettre dans chaque jsp une ouverture de session hibernate en début et une fermeture en fin? je ne pense pas que c'est la solution non plus...
    Je ne souhaite pas utiliser le mode "eager". Le chargement à la demande m'a l'air mieux car ca ne va pas tout charger dès le début.

    OButterlin : dans un précédent message vous disiez :
    Dans mon exemple, effectivement, il n'y a pas l'ouverture/fermeture de la session parce que c'est géré au niveau d'un filtre.
    La session est ouverte en début de request et fermée en fin de response.
    .
    Comment faire cela sachant qu'il y a deja un filtre sur mon application :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
        <filter>
            <filter-name>struts2</filter-name>
            <filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class>
        </filter>
     
        <filter-mapping>
            <filter-name>struts2</filter-name>
            <url-pattern>/*</url-pattern>
        </filter-mapping>
    Merci d'avance

    Quelqu'un sait

  2. #2
    Modérateur
    Avatar de OButterlin
    Homme Profil pro
    Inscrit en
    Novembre 2006
    Messages
    7 311
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Novembre 2006
    Messages : 7 311
    Points : 9 525
    Points
    9 525
    Billets dans le blog
    1
    Par défaut
    Je ne connais pas struts2 mais j'étendrais la classe en redéfinissant la méthode doFilter(...)
    Quelque chose comme 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
    20
    ...
        public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException
        {
            try
            {
                // on ouvre éventuellement la session ici
    
                chain.doFilter(request, response);
            }
            catch (Throwable t)
            {
                System.out.println("doFilter error : " + t.toString());
            }
            finally
            {
                // on ferme la session ici
            }
        }
    ...
    Mais bon, comme dit, je ne connais pas struts2 et je ne sais pas ce que fait ce filtre, donc, c'est sans garantie
    N'oubliez pas de consulter les FAQ Java et les cours et tutoriels Java

  3. #3
    Nouveau membre du Club
    Inscrit en
    Août 2011
    Messages
    109
    Détails du profil
    Informations forums :
    Inscription : Août 2011
    Messages : 109
    Points : 32
    Points
    32
    Par défaut
    J'ai lu qu'on pouvais avoir deux filtres déclarés dans le sens des <filter-mapping>.

    Donc quand vous dites :
    j'étendrais la classe
    , il suffit que je crée un deuxième filtre (placé en premier) avec le code donné qui ne fait qu'ouvrir et fermer la connexion hiberate.

    A suivre...

  4. #4
    Expert éminent sénior
    Avatar de tchize_
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Avril 2007
    Messages
    25 481
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 44
    Localisation : Belgique

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

    Informations forums :
    Inscription : Avril 2007
    Messages : 25 481
    Points : 48 806
    Points
    48 806
    Par défaut
    Le plus propre est d'avoir effectivement un deuxième filtre qui ouvre et ferme la session hibernate. Et tu mappe ce filtre sur les requête qui utilisent hibernate. Donc a priori sur struts


    Par contre, etendre le filtre Struts => beurk, ça n'a aucun intérêt selon moi.

  5. #5
    Modérateur
    Avatar de OButterlin
    Homme Profil pro
    Inscrit en
    Novembre 2006
    Messages
    7 311
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Novembre 2006
    Messages : 7 311
    Points : 9 525
    Points
    9 525
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par tchize_ Voir le message
    Le plus propre est d'avoir effectivement un deuxième filtre qui ouvre et ferme la session hibernate. Et tu mappe ce filtre sur les requête qui utilisent hibernate. Donc a priori sur struts

    Par contre, etendre le filtre Struts => beurk, ça n'a aucun intérêt selon moi.
    Je n'utilise pas struts2 donc je ne sais pas trop ce qu'est sensé faire le filtre mais en struts1, j'étendais le préprocesseur de struts, c'était bien plus intéressant qu'un simple filtre.

    Ceci dit, oui, on tu peux créer un autre filtre et le placer devant, pas de soucis...
    N'oubliez pas de consulter les FAQ Java et les cours et tutoriels Java

  6. #6
    Nouveau membre du Club
    Inscrit en
    Août 2011
    Messages
    109
    Détails du profil
    Informations forums :
    Inscription : Août 2011
    Messages : 109
    Points : 32
    Points
    32
    Par défaut
    Cela fonctionne en gérant un second filtre.

    Par contre, j'ai une question sur (pas sur la même erreur), mais qui concerne le meme objet (Tarif et TarifValeur).

    Je n'avais pas de problème avant l'utilisation d'Hibernate. Il doit donc y avoir une subtilité.
    Avec Hibernate, le tarifvaleurs est un set, alors qu'avant, avec mes dao manuelles, je faisais un arrayList.

    La page de modification est la suivante : formulaire sur le tarif modifiable et formulaire sur la liste des valeurs (non modifiable) mais qui s'affiche en dessous pour que la liste des valeurs du tarifs soit transmise lors du sumit :
    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
     
    			<s:form name="tarifForm" action="">
    				<s:textfield name="tarif.tarId" readonly="true" 
    					label="%{getText('label.tarif.id')}" />
    				<s:textfield name="tarif.tarLibelle" required="true"
    					label="%{getText('label.tarif.libelle')}" />
    				<s:textfield name="tarif.tarNomArticle" required="true"
    					label="%{getText('label.tarif.nomArticle')}" />
    				<s:textfield name="tarif.tarGroupeMarchandise" required="true"
    					label="%{getText('label.tarif.groupeMarchandise')}" />
     
    				<table id="TarifValeur" class="tablesorter">
    			<thead>...</thead>
    			<tbody>
     
    				<s:iterator  value="tarif.cpteTarifvaleurs" var="tarifValeur" status="status"  >
    				<tr>
    					<td><s:textfield theme="simple" cssClass="inputReadOnlyTransparent" readonly="true" name="tarif.cpteTarifvaleurs[%{#status.index}].valId" value="%{valId}"/></td>
    					<td><s:textfield theme="simple" cssClass="inputReadOnlyTransparent" readonly="true" name="tarif.cpteTarifvaleurs[%{#status.index}].valDateEffet" value="%{valDateEffet}"/></td>
    					<td><s:textfield theme="simple" cssClass="inputReadOnlyTransparent" readonly="true" name="tarif.cpteTarifvaleurs[%{#status.index}].valDateFin" value="%{valDateFin}"/></td>
    					<td><s:textfield theme="simple" cssClass="inputReadOnlyTransparent" readonly="true" name="tarif.cpteTarifvaleurs[%{#status.index}].valMontant" value="%{valMontant}"/></td>
    					<td>
    				</tr>
    				</s:iterator>
    Les valeurs du tarifs s'affichent correctement, mais à la validation du formulaire, j'ai des erreurs sur tous les champs du tableau :
    2014-03-07 09:45:56,577 WARN com.opensymphony.xwork2.ognl.OgnlValueStack - Error setting expression 'tarif.cpteTarifvaleurs[0].valId' with value '[Ljava.lang.String;@65919c1f'
    ognl.NoSuchPropertyException: java.util.HashSet.0

    Cela se comprends car l'id est un long, les dates sont des dates et le montant est un bigDecimal donc pas des String.

    Pour votre information, je suis obligé de mettre la liste dans un textField car si je fais un tableau basique, les champs sont perdu si la validation du formulaire ci-dessus (via les fichier_validation.xml) retourne un fieldError.

    Cdt.

  7. #7
    Expert éminent sénior
    Avatar de tchize_
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Avril 2007
    Messages
    25 481
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 44
    Localisation : Belgique

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

    Informations forums :
    Inscription : Avril 2007
    Messages : 25 481
    Points : 48 806
    Points
    48 806
    Par défaut
    Non, le problème il est là:

    NoSuchPropertyException: java.util.HashSet.0


    En gros ,tu essaie d'accéder à l'index 1 d'un Hashset. Un hashset n'a pas d'index et n'est donc pas accessible comme cela, contrairement à un arraylist.

    Je ne connais pas des masses Struts, mais je suppose que ça a a voir avec ça


    tarif.cpteTarifvaleurs[%{#status.index}].valDateEffet

    qui n'a pas de sens avec un Set.


    Je te propose plusieurs voies d'exploration

    1) en priorité, voir avec struts comment tu peux gérer via un Set, est-ce que c'est possible?
    2) regarder si il est possible d'utiliser un SortedSet plutot qu'un Set? Ceux là sont indexable, mais alors, quel critère d'indexation? Comment gérer la mutabilité du contenu?
    3) regarder à créer une propriété dérivée, transient, qui expose le Set comme un ArrayList.

  8. #8
    Nouveau membre du Club
    Inscrit en
    Août 2011
    Messages
    109
    Détails du profil
    Informations forums :
    Inscription : Août 2011
    Messages : 109
    Points : 32
    Points
    32
    Par défaut
    Ca doit etre lié, mais ce n'est pas un problème à l'accès à la donnée, mais à la validation du formulaire.

  9. #9
    Nouveau membre du Club
    Inscrit en
    Août 2011
    Messages
    109
    Détails du profil
    Informations forums :
    Inscription : Août 2011
    Messages : 109
    Points : 32
    Points
    32
    Par défaut
    Pour contourner le problème, j'ai essayé de remplacé le mapping fait par HibernateTools (qui avait fait des "set"), par des list.
    J'ai donc fait :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     
    <list name="cpteTarifvaleurs" inverse="true" table="CPTE_TARIFVALEUR" lazy="true" cascade="all" fetch="select">
                <key>
                    <column name="TAR_ID" precision="22" scale="0" not-null="true" />
                </key>
                <index>
                    <column name="VAL_ID" />
                </index>
                <one-to-many class="cpte.hibernate.CpteTarifvaleur" />
            </list>
    donc : remplacé les "set" par "list", mis un "index" avec l'id de la valeur.

    Le seul problème est que lorsque je charge cette liste :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    tarif = CpteTarifDao.getInstance().get(4); 
    List a = tarif.getCpteTarifvaleurs();
    Je me rend compte que la liste ne contient pas seulement la valeur en base de données :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    2014-03-07 13:49:41,400 DEBUG cpte.dao.CpteTarifDao - get(id) 4
    Hibernate: select cptetarif0_.TAR_ID as TAR_ID1_1_0_, cptetarif0_.TAR_LIBELLE as TAR_LIBELLE2_1_0_, cptetarif0_.TAR_NOM_ARTICLE as TAR_NOM_ARTICLE3_1_0_
    , cptetarif0_.TAR_GROUPE_MARCHANDISE as TAR_GROUPE_MARCHAN4_1_0_ from .CPTE_TARIF cptetarif0_ where cptetarif0_.TAR_ID=?
    Hibernate: select cptetarifv0_.TAR_ID as TAR_ID2_1_0_, cptetarifv0_.VAL_ID as VAL_ID1_2_0_, cptetarifv0_.VAL_ID as VAL_ID1_0_, 
    cptetarifv0_.VAL_ID as VAL_ID1_2_1_, cptetarifv0_.TAR_ID as TAR_ID2_2_1_, cptetarifv0_.VAL_DATE_EFFET as VAL_DATE_EFFET3_2_1_,
     cptetarifv0_.VAL_DATE_FIN as VAL_DATE_FIN4_2_1_, cptetarifv0_.VAL_MONTANT as VAL_MONTANT5_2_1_ from .CPTE_TARIFVALEUR cptetarifv0_ where cptetarifv0_.TAR_ID=?
    En débugant :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    a =
    [null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, 
    null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, 
    null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
     null, null, null, null, null, null, null, cpte.hibernate.CpteTarifvaleur@3d317ab]
    --> J'ai bien qu'une valeur dans mon cas, mais je me serai attendu à avoir une liste ne contenant qu'un élément et pas X éléments NULL avant (ce qui est génant lors de l'affichage...)

    Qu'en pensez vous?

  10. #10
    Expert éminent sénior
    Avatar de tchize_
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Avril 2007
    Messages
    25 481
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 44
    Localisation : Belgique

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

    Informations forums :
    Inscription : Avril 2007
    Messages : 25 481
    Points : 48 806
    Points
    48 806
    Par défaut
    Ben tu lui a dit que l'index c'était l'id, il a donc positionné la valeur à l'index en question.

    Si tu veux juste trier par Id => SortedSet, comme je l'ai dit. Tout ce qui est List en hibernate requiert de stocker dans la base l'index du tableau.

  11. #11
    Nouveau membre du Club
    Inscrit en
    Août 2011
    Messages
    109
    Détails du profil
    Informations forums :
    Inscription : Août 2011
    Messages : 109
    Points : 32
    Points
    32
    Par défaut
    J'avais essayé list uniquement pour pouvoir la passer dans le formulaire.
    Mais vu que je ne stocke pas de la tri en base, il faut que n'abandonne cette idée.

    Je vais continuer a utiliser un set. Je n'ai pas besoin de tri. Il faut juste que je réussisse a la passer dans le formulaire afin qu'elle soit toujours affichée en cas d'erreur de saisie sur les champs modifiable du formulaire.

    la solution est peut être de mettre cette liste dans la session (pas hibernate), comme ça les valeurs (tarifvaleur) ne seront pas perdue (à l'affichage) lors de la validation du formulaire sur le tarif... a suivre

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

Discussions similaires

  1. Réponses: 2
    Dernier message: 18/01/2015, 19h05
  2. Failed to lazily initialize a collection
    Par Grumium dans le forum Hibernate
    Réponses: 8
    Dernier message: 27/10/2009, 16h35
  3. Réponses: 5
    Dernier message: 23/10/2009, 14h02
  4. failed to lazily initialize a collection of role ?
    Par zuzuu dans le forum Hibernate
    Réponses: 3
    Dernier message: 25/02/2009, 16h02
  5. Réponses: 1
    Dernier message: 04/04/2007, 09h17

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