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(); } }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.
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()); } }
Ces entités JPA sont accessibles par un EJB stateless+interface distance.
Là aussi rien de bien compliqué non plus.
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; } }
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 :
Je vais avoir une exception sur le LazyLoading :
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()); }
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.
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)
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.
Partager