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

  1. #1
    Membre éprouvé
    EJB stateless et JPA sont sur un bateau. . . et le client est sur la terre ferme
    Bonjour à tous,

    J'ai un problème de compréhension/mise en application de JPA au sein d'un EJB stateless et des chargements à la demande. Je vais exprimer mon problème avec un exemple tout simple.

    Voici les entity JPA :
    Personnes :
    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
    package cnam.entite;
     
    import static javax.persistence.CascadeType.MERGE;
    import static javax.persistence.CascadeType.PERSIST;
    import static javax.persistence.CascadeType.REMOVE;
    import static javax.persistence.CascadeType.ALL;
    import static javax.persistence.FetchType.LAZY;
     
    import java.io.Serializable;
    import java.sql.Timestamp;
    import java.util.List;
     
    import javax.persistence.Entity;
    import javax.persistence.FetchType;
    import javax.persistence.GeneratedValue;
    import javax.persistence.GenerationType;
    import javax.persistence.Id;
    import javax.persistence.JoinColumn;
    import javax.persistence.OneToMany;
    import javax.persistence.OneToOne;
    import javax.persistence.Table;
     
    @Entity
    @Table(name="t_client", schema = "ecommerce")
    public class Client implements Serializable {
    	@Id
    	@GeneratedValue(strategy=GenerationType.AUTO)
    	private int identifiant;
     
    	private String nom;
     
     
    	private Timestamp datenaissance;
     
    	private String password;
     
    	@OneToOne(cascade=ALL, fetch = FetchType.LAZY)
    	@JoinColumn(name="fk_id_adresse")
    	private Adresse adresse;
     
    	private String prenom;
     
    	private String email;
     
    	private String login;
    	private static final long serialVersionUID = 1L;
     
    	//getter & setter
    	public String toString(){
    		StringBuffer sb=new StringBuffer("Id : "+getIdentifiant()+" Nom : ");
    		sb.append(getNom());
    		sb.append(" Prenom : ");
    		sb.append(getPrenom());
    		return sb.toString();
    	}	
    }


    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
    package cnam.entite;
     
    import java.io.Serializable;
     
    import javax.persistence.Entity;
    import javax.persistence.GeneratedValue;
    import javax.persistence.GenerationType;
    import javax.persistence.Id;
    import javax.persistence.Table;
     
    @Entity
    @Table(name="t_adresse", schema = "ecommerce")
    public class Adresse implements Serializable {
    	@Id
    	@GeneratedValue(strategy=GenerationType.AUTO)
    	private int id;
     
    	private String adr4;
     
    	private String ville;
     
    	private String adr1;
     
    	private String adr3;
     
    	private int codepostal;
     
    	private String adr2;
     
    	private static final long serialVersionUID = 1L;
     
    	public Adresse() {
    		super();
    	}
    	//getters et setters
     
    	@Override
    	public String toString() {
    		return String.format("[%d, %s,%s, %s, %s, %d, %s]", getId(),getAdr1(),getAdr2(),getAdr3(), getAdr4(),getCodepostal(),getVille());
    	}
    }

    Comme vous pouvez le voir, c'est un exemple très classique. Lors que je fais des tests locaux avec un entityManager créé en dehors d'un serveur d'application. La méthode getAdresse() s'exécute correctement et me ramène les adresses des clients lorsque j'en ai le besoin.



    Ces entités JPA sont accessibles par un EJB stateless+interface distance.
    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
    @Stateless
    public class ClientBean implements ClientLocal, ClientRemote {
    	@PersistenceContext(unitName="EcommerceEJB-JNDI")
    	private EntityManager em;
     
    	public Client createClient(Client client, Adresse adresse) {
    		client.setAdresse(adresse);
    		em.persist(client);
    		return client;
    	}
     
    	public Client createClient(Client client) {		
    		em.persist(client);
    		return client;
    	}
    	public Client rechercherClientById(int id){
    		return em.find(Client.class, id);
    	}
    	public void deleteClient(Client client) {
    		client=em.merge(client);
    		em.remove(client);
    	}
    	public Client updateClient(Client client) {
    		client=em.merge(client);
    		return client;
    	}
    	@SuppressWarnings("unchecked")
    	public List<Client> getClients(){
    		Query clients=em.createQuery("Select c from Client c");
    		List<Client> res=(List<Client>)clients.getResultList();
    		return res;
    	}
    }

    Là aussi rien de bien compliqué non plus.

    Et là j'ai mon problème avec mon programme client de cet EJB et le chargement des adresses.
    Si mon client effectue cette boucle :
    Code :Sélectionner tout -Visualiser dans une fenêtre à part
    1
    2
    3
    4
    for (Client client : clientBean.getClients()) {
    			System.out.println("Clien :"+client.getIdentifiant());
    			System.out.println("Clien :"+client.getAdresse());
    		}

    Je vais avoir une exception sur le LazyLoading :
    Code :Sélectionner tout -Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    Exception in thread "main" org.hibernate.LazyInitializationException: could not initialize proxy - no Session
    	at org.hibernate.proxy.AbstractLazyInitializer.initialize(AbstractLazyInitializer.java:57)
    	at org.hibernate.proxy.AbstractLazyInitializer.getImplementation(AbstractLazyInitializer.java:111)
    	at org.hibernate.proxy.pojo.javassist.JavassistLazyInitializer.invoke(JavassistLazyInitializer.java:166)
    	at cnam.entite.Adresse_$$_javassist_0.toString(Adresse_$$_javassist_0.java)
    	at java.lang.String.valueOf(String.java:2615)
    	at java.lang.StringBuilder.append(StringBuilder.java:116)
    	at cnam.entite.test.ClientBeanTest.main(ClientBeanTest.java:44)


    Si dans mon entité client, je mets "fetch=EAGER", le code s'exécute correctement. Ce qui est logique puisque l'adresse est chargée lors de la récupération des clients.

    En résumé, je ne vois pas comment gérer proprement les lazy loading dans mon programme client. Je ne me vois pas mettre les fetch à EAGER sur toute mes associations (aie les performances). Et créer des méthodes dans mes EJB du style "Adresse getAdresse(Client cli)" me semble bien lourd.
    Je me dis que je suis passé à coté de quelques choses, mais je ne vois pas ce que c'est. Et les cours que j'ai pu trouver ici et là ne parle quasiment pas de ce problème.

    Le reste de ma configuration : JBoss AS 4.2 + hibernate +mysql

    Merci d'avance pour votre aide.

  2. #2
    Membre éclairé
    Bonsoir,
    Juste une question : est ce normal que les deux serialVersionUID des deux classes soient égaux ?

    Et si tu mettais des valeurs différentes, ça donne quoi ?
    Where is my mind

  3. #3
    Membre éprouvé
    Bonjour, merci de ta réponse,.
    Citation Envoyé par bassim Voir le message
    Bonsoir,
    Juste une question : est ce normal que les deux serialVersionUID des deux classes soient égaux ?
    Ils sont issus de la génération de code par eclipse, je ne les ai pas modifiés.


    Et si tu mettais des valeurs différentes, ça donne quoi ?
    Je n'ai pas le code sous la main pour tester, je te donnerai le résultat avec cette modification dés que je le pourrais.

  4. #4
    Membre éprouvé
    Suite de mon histoire.

    Afin de conserver le lazy loading, j'ai implémenter des méthodes(genre "getFullPersonFromId(int id)") dans mes ejb qui s'occupe de précharger ces données.
    Avec ce genre de méthode cela fonctionne.


    Si il y a une meilleure méthode pour procéder, je suis preneur.

  5. #5
    Expert éminent
    Bonjour,
    Et si tu ajoutes type = PersistenceContextType.EXTENDED comme second attribut à ton annotation @PersistenceContext ... ça marche dans le serveur, mais je n'en suis pas sûr pour un client distant ...

  6. #6
    Membre éprouvé
    Citation Envoyé par djo.mos Voir le message
    Bonjour,
    Et si tu ajoutes type = PersistenceContextType.EXTENDED comme second attribut à ton annotation @PersistenceContext ... ça marche dans le serveur, mais je n'en suis pas sûr pour un client distant ...
    J'avais essayé une fois de mettre cette options, mais le déploiement échouait.

###raw>template_hook.ano_emploi###