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 :

[ManyToMany] problème de bean entité détaché


Sujet :

Hibernate Java

  1. #1
    Membre du Club
    Profil pro
    Inscrit en
    Février 2007
    Messages
    64
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations forums :
    Inscription : Février 2007
    Messages : 64
    Points : 54
    Points
    54
    Par défaut [ManyToMany] problème de bean entité détaché
    Bonsoir,


    J'ai un problème avec JBoss/Hibernate concernant les relations "manyToMany"...

    J'ai 2 beans entités:
    - user
    - role

    En toute logique, un "user" peut posséder 1 ou plusieurs "role" ... Pareil pour un "role"; je dirais meme plus: cela peut varier de 0 à plusieurs ...

    Donc j'ai créé mes beans entité de la sorte:

    User.java:
    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
    //by loopx
    //08/01/08
     
    package be.loopx.pixmania.ejb.entity;
     
    import java.io.Serializable;
    import java.lang.reflect.Array;
    import java.util.ArrayList;
    import java.util.List;
     
    import javax.persistence.CascadeType;
    import javax.persistence.Column;
    import javax.persistence.Entity;
    import javax.persistence.GeneratedValue;
    import javax.persistence.GenerationType;
    import javax.persistence.Id;
    import javax.persistence.ManyToMany;
    import javax.persistence.SequenceGenerator;
    import javax.persistence.Table;
     
    @Entity
    @Table(name="user")
    public class User implements Serializable {
    	private static final long serialVersionUID = 1L;
     
    	private int id;
    	private String login;
    	private String password;
    	private List<Role> roles=new ArrayList<Role>();
     
    	public void setLogin(String login) {
    		this.login = login;
    	}
    	@Column(length=20, nullable=false, unique=true)
    	public String getLogin() {
    		return login;
    	}
     
    	public void setPassword(String password) {
    		this.password = password;
    	}
    	@Column(length=20, nullable=false)
    	public String getPassword() {
    		return password;
    	}
     
    	public void setId(int id) {
    		this.id = id;
    	}
    	@Id
    	@GeneratedValue(strategy = GenerationType.AUTO)
    	public int getId() {
    		return id;
    	}
     
    	public void setRoles(List<Role> roles) {
    		this.roles=roles;
    	}
     
    	@ManyToMany(mappedBy="users", cascade={CascadeType.ALL})
    	public List<Role> getRoles() {
    		return this.roles;
    	}
    }
    Role.java:
    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
    package be.loopx.pixmania.ejb.entity;
     
    import java.io.Serializable;
     
    @Entity
    @Table(name="role")
    public class Role implements Serializable {
    	private static final long serialVersionUID = 1L;
     
    	private int id;
    	private String name;
    	private List<User> users=new ArrayList<User>();
     
    	public void setName(String n) {
    		this.name = n;
    	}
    	@Column(length=50, nullable=false, unique=true)
    	public String getName() {
    		return name;
    	}
     
    	public void setId(int id) {
    		this.id = id;
    	}
    	@Id
    	@GeneratedValue(strategy = GenerationType.AUTO)
    	public int getId() {
    		return id;
    	}
     
    	public void setUsers(List<User> users) {
    		this.users = users;
    	}
    	@ManyToMany
    	public List<User> getUsers() {
    		return users;
    	}
    }
    J'ai ajouté (dans les 2 entités) des List contenant les beans entité qui lui sont lié.

    J'ai eu une erreur pendant un moment, je viens de comprendre ce que c'était. Voici l'erreur:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     
    01:56:30,346 ERROR [LazyInitializationException] failed to lazily initialize a collection of role: be.loopx.pixmania.ejb.entity.User.roles, no session or session was closed
    org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: be.loopx.pixmania.ejb.entity.User.roles, no session or session was closed
            at org.hibernate.collection.AbstractPersistentCollection.throwLazyInitializationException(AbstractPersistentCollection.java:358)
            at org.hibernate.collection.AbstractPersistentCollection.throwLazyInitializationExceptionIfNotConnected(AbstractPersistentCollection.java:350)
            at org.hibernate.collection.AbstractPersistentCollection.readSize(AbstractPersistentCollection.java:97)
            at org.hibernate.collection.PersistentBag.size(PersistentBag.java:225)
            at be.loopx.pixmania.ejb.facade.UserFacadeBean.addRoleToUser(UserFacadeBean.java:63)
    En fait, un module web (.war) est client des EJB (plus précisément, une servlet). Celle-ci communique via ce schéma:

    Servlet => privateEJB(session stateful) => userEJB_facade(session stateless) => entity => base de donnée

    Voici la méthode "addRoleToUser" de la facade "UserFacadeBean":
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    public void addRoleToUser(Role role, User user) {		
    		role.getUsers().add(user);	//add 1 user to the role
    		user.getRoles().add(role);	//add 1 role to the user
     
                    em.merge(user);
    	}
    Cette méthode est appelée par le bean stateful "privateEJB" dont voici un extrait:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     
    //bind administrator to admin
    		usersList=userEJB_facade.listFiltered("where o.login='admin'");
    		rolesList=roleEJB_facade.listFiltered("where o.name='administrator'");
    		System.out.print(this.getClass().getName()+"> USER="+usersList.get(0).getLogin()+" / ROLE="+rolesList.get(0).getName());	
     
    		userEJB_facade.addRoleToUser(rolesList.get(0), usersList.get(0));
    Ce code est situé dans le constructeur du bean session stateful. Quand un client se connecte au module Web (via le navigateur), la servlet est instanciée. Dans chaque session HTTP, le bean privateEJB est injecté.

    Pour les tests (actuellement), lors de l'instanciation du bean privateEJB, je crée le user "admin" et le role "administrator": aucun problème (dans la bd, j'ai tout ce qu'il faut, y compris une table "role_user" contenant (enfin, ne contenant encore rien) les liens entre user et role.

    La méthode "addRoleToUser" est la pour pour lié ces 2 entités. Seulement voilà, j'ai l'erreur de "lazy" cité plus haut. J'ai trouvé pourquoi: dans la facade utilisateur (dans la méthode "addRoleToUser"), je récupère 2 beans entités. Ceux-ci sont considéré comme "non attaché" ce qui pose donc le problème de "lazy". Pour tester, j'ai ajouter cette ligne dans la méthode d'ajout d'un role:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    user=findById(user.getId());	//re-attach user
    AVANT le:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    user.getRoles().add(role);	//add 1 role to the user
    de manière à re-attacher le bean entité ... L'erreur est passé ... enfin non, puisque j'ai le meme souci avec le bean entité "role" passé à la méthode:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    02:07:30,991 WARN  [arjLoggerI18N] [com.arjuna.ats.arjuna.coordinator.TwoPhaseCoordinator_2] TwoPhaseCoordinator.beforeCompletion - failed for com.arjuna.ats.internal.jta.resources.arjunacore.SynchronizationImple@1a46497
    javax.persistence.PersistenceException: org.hibernate.PersistentObjectException: detached entity passed to persist: be.loopx.pixmania.ejb.entity.Role


    Alors voilà, je me rend compte de ceci: je ne peux pas faire un "findById" sur chaque entité dans la facade utilisateur (userEJB_facade), logique (regardez le schéma ci-dessous

    privateEJB => *EJB_facade => Entity => base de donnée
    Il m'est impensable de faire l'injection de la facade "role" dans la facade "user"! Donc, le "truc" de l'ajout de la ligne permettant de ratacher le bean entité "user" dans la facade utilisateur est donc à annuler. Il faut que cela se passe AVANT l'appel à la facade!


    J'essaie donc de modifier le bean privateEJB (son constructeur) de manière à ce qu'il soit ainsi:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    //bind administrator to admin
    		usersList=userEJB_facade.listFiltered("where o.login='admin'");
    		rolesList=roleEJB_facade.listFiltered("where o.name='administrator'");
    		System.out.print(this.getClass().getName()+"> USER="+usersList.get(0).getLogin()+" / ROLE="+rolesList.get(0).getName());		
     
    		User user=userEJB_facade.findById(usersList.get(0).getId());
    		//userEJB_facade.addRoleToUser(rolesList.get(0), usersList.get(0));
    		userEJB_facade.addRoleToUser(rolesList.get(0), user);
    en conclusion, avant l'appel à "addRoleToUser", j'essaie de re-attacher le user. J'ai plusieurs question à ce sujet:
    - pourquoi est-ce que la méthode de recherche (avec du code EJBQL) n'a t'elle pas attaché le bean entité USER et ROLE ??
    - pourquoi est-ce que un "findById" juste avant la facade ne fonctionne pas ?

    Parce que le problème est bien la: impossible d'attacher le bean USER (trouvé avec la requette login=admin) AVANT l'appel à la méthode "addRoleToUser". Je bloque, pour tout vous dire, ca fait 1 semaine que je me casse la tête, et rien n'avance. Je pense que j'ai un problème de logique dans le développement ou alors, un problème de "relation" entre bean.

    Je précise que l'erreur (après avoir ajouté le findbyid du user dans le constructeur du bean privateEJB) est exactement la meme que au tout début (donc, le findbyid placé dans privateEJB ne fonctionne pas, alors que si je l'appel quand je suis dans la facade, cela fonctionne).


    Voilà, je suis perdu, je pense que je n'y arriverais jamais sans une petite aide de votre part. Donc, je vous remercie d'avance de me lire.

    EDIT: j'ai d'autre question:
    - qu'elle est la méthode "correct" pour attaché un bean ? (findById ?)
    - est-ce que la méthode utilisée pour "lier" 2 beans entité est correct ?
    - un ptit tuto peut etre, avec exemple parce que, je bloque...

    EDIT2: voici une mini partie des logs, pour ceux que ca intéresse ...
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    02:49:12,031 INFO  [[/web_base]] be.loopx.pixmania.servlet.ControlServlet> All context have been initialized
    02:49:12,062 INFO  [STDOUT] be.loopx.pixmania.ejb.session.PrivateBean> All context have been initialized
    02:49:12,246 INFO  [STDOUT] be.loopx.pixmania.ejb.session.PrivateBean> USER=admin / ROLE=administrator
    actuellement, après ces logs, j'ai les erreurs cité plus haut

  2. #2
    Membre régulier
    Profil pro
    Inscrit en
    Juin 2007
    Messages
    74
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2007
    Messages : 74
    Points : 83
    Points
    83
    Par défaut
    Pb assez courant... la solution ? il en existe plusieurs, plus ou difficile à mettre en oeuvre et/ou à expliquer ici...
    résumons un peu: Dans ton stateful, tu as certainement injecté un entotyManager de type TRANSACTION (type par défaut). et tu n'as certainemnet que des méthode de type Required (comportement transac par défaut des ejb3 session):

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
     
    @Stateful
    public class SFSB implements ... {
    	@PersistenceContext(name = "maPU", type = PersistenceContextType.TRANSACTION)
    	EntityManager em;
     
    	@TransactionAttribute(value = TransactionAttributeType.REQUIRED)
    	public void myMethod() {...]
    Ce qui revient à dire finalement que l'entityManager est crée a l'entrée de l'une des méthodes et est fermé au commit de la transaction (i.e. au sortir de ta méthode)

    Conséquence: Si l'une de tes méthodes charge un objet persistant, alros cet objet sera détaché à la fin de la méthode. et tu t'expose à des problemes de chargement tardifs (LazyInitialisationException) sur les collections non chargées. c'est le cas pour toute tes méthodes mentionnées ci d-dessous:
    • listFiltered
    • findById

    Je précise que l'erreur (après avoir ajouté le findbyid du user dans le constructeur du bean privateEJB) est exactement la meme que au tout début (donc, le findbyid placé dans privateEJB ne fonctionne pas, alors que si je l'appel quand je suis dans la facade, cela fonctionne).
    Normal, le findById fonctionne quand tu le mets directement dans la façade car tu l'appelles alors que la transaction courante n'est pas encore commité=> l'entityManager est toujours ouvert...

    Plusieurs solutions:

    la plus simple à tester: EntityManager.EXTENDED (à la seam)
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    @Stateful
    public class SFSB implements ... {
    	@PersistenceContext(name = "maPU", type = PersistenceContextType.EXTENDED)
    	EntityManager em;
    La durée de vie de ton entityManager est maintenant lié à ton ejb stateful (attention EXTENDED n'a de sens que pour les stateful); les objets persistent qu'il va te permettre de lire seront toujours attaché au ctxt de persistence tant que tu n'as pas appelé la méthode @Remove de ton stateful...
    Cette pratique présente des désavantage: si ton stateful a une durée de vie longue, la probabilité de désynchrnisé les valeurs lues précédemment et celle présente en base est grand (=> utilisation de verrou optimiste conseillé)
    En relisant ton mail, je pense donc que ton UserEJB_facade deveint stateful pour des raisons techniques.

    Tu n'as alors plus besoin du merge dans addRoleToUser puisque ces objets sont toujours attachés


    Deuxième solution:
    Au moment de charger un User, tu charges les Rôles qui lui sont associés avec une requête JPQL:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    User u = m.createQuery("From User u join fetch u.roles where u.name=...")
    Remarque: si tu restes en entityManager TRANSACTION, l'objet u qui sera retourné par ta facade contiendra la collection de Role mais restera détaché du contexte (merge obligatoire dans addRoleToUser)

    un ptit tuto peut etre, avec exemple parce que, je bloque...
    Lire les specs JPA ? Je ne connais aucun livre bien fait sur JPA... Tous ceux que j'ai pu feuilleter contiennent des boulettes :-(





    Citation Envoyé par loopx Voir le message
    Bonsoir,


    J'ai un problème avec JBoss/Hibernate concernant les relations "manyToMany"...

    J'ai 2 beans entités:
    - user
    - role

    En toute logique, un "user" peut posséder 1 ou plusieurs "role" ... Pareil pour un "role"; je dirais meme plus: cela peut varier de 0 à plusieurs ...

    Donc j'ai créé mes beans entité de la sorte:

    User.java:
    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
    //by loopx
    //08/01/08
     
    package be.loopx.pixmania.ejb.entity;
     
    import java.io.Serializable;
    import java.lang.reflect.Array;
    import java.util.ArrayList;
    import java.util.List;
     
    import javax.persistence.CascadeType;
    import javax.persistence.Column;
    import javax.persistence.Entity;
    import javax.persistence.GeneratedValue;
    import javax.persistence.GenerationType;
    import javax.persistence.Id;
    import javax.persistence.ManyToMany;
    import javax.persistence.SequenceGenerator;
    import javax.persistence.Table;
     
    @Entity
    @Table(name="user")
    public class User implements Serializable {
    	private static final long serialVersionUID = 1L;
     
    	private int id;
    	private String login;
    	private String password;
    	private List<Role> roles=new ArrayList<Role>();
     
    	public void setLogin(String login) {
    		this.login = login;
    	}
    	@Column(length=20, nullable=false, unique=true)
    	public String getLogin() {
    		return login;
    	}
     
    	public void setPassword(String password) {
    		this.password = password;
    	}
    	@Column(length=20, nullable=false)
    	public String getPassword() {
    		return password;
    	}
     
    	public void setId(int id) {
    		this.id = id;
    	}
    	@Id
    	@GeneratedValue(strategy = GenerationType.AUTO)
    	public int getId() {
    		return id;
    	}
     
    	public void setRoles(List<Role> roles) {
    		this.roles=roles;
    	}
     
    	@ManyToMany(mappedBy="users", cascade={CascadeType.ALL})
    	public List<Role> getRoles() {
    		return this.roles;
    	}
    }
    Role.java:
    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
    package be.loopx.pixmania.ejb.entity;
     
    import java.io.Serializable;
     
    @Entity
    @Table(name="role")
    public class Role implements Serializable {
    	private static final long serialVersionUID = 1L;
     
    	private int id;
    	private String name;
    	private List<User> users=new ArrayList<User>();
     
    	public void setName(String n) {
    		this.name = n;
    	}
    	@Column(length=50, nullable=false, unique=true)
    	public String getName() {
    		return name;
    	}
     
    	public void setId(int id) {
    		this.id = id;
    	}
    	@Id
    	@GeneratedValue(strategy = GenerationType.AUTO)
    	public int getId() {
    		return id;
    	}
     
    	public void setUsers(List<User> users) {
    		this.users = users;
    	}
    	@ManyToMany
    	public List<User> getUsers() {
    		return users;
    	}
    }
    J'ai ajouté (dans les 2 entités) des List contenant les beans entité qui lui sont lié.

    J'ai eu une erreur pendant un moment, je viens de comprendre ce que c'était. Voici l'erreur:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     
    01:56:30,346 ERROR [LazyInitializationException] failed to lazily initialize a collection of role: be.loopx.pixmania.ejb.entity.User.roles, no session or session was closed
    org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: be.loopx.pixmania.ejb.entity.User.roles, no session or session was closed
            at org.hibernate.collection.AbstractPersistentCollection.throwLazyInitializationException(AbstractPersistentCollection.java:358)
            at org.hibernate.collection.AbstractPersistentCollection.throwLazyInitializationExceptionIfNotConnected(AbstractPersistentCollection.java:350)
            at org.hibernate.collection.AbstractPersistentCollection.readSize(AbstractPersistentCollection.java:97)
            at org.hibernate.collection.PersistentBag.size(PersistentBag.java:225)
            at be.loopx.pixmania.ejb.facade.UserFacadeBean.addRoleToUser(UserFacadeBean.java:63)
    En fait, un module web (.war) est client des EJB (plus précisément, une servlet). Celle-ci communique via ce schéma:

    Servlet => privateEJB(session stateful) => userEJB_facade(session stateless) => entity => base de donnée

    Voici la méthode "addRoleToUser" de la facade "UserFacadeBean":
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    public void addRoleToUser(Role role, User user) {		
    		role.getUsers().add(user);	//add 1 user to the role
    		user.getRoles().add(role);	//add 1 role to the user
     
                    em.merge(user);
    	}
    Cette méthode est appelée par le bean stateful "privateEJB" dont voici un extrait:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     
    //bind administrator to admin
    		usersList=userEJB_facade.listFiltered("where o.login='admin'");
    		rolesList=roleEJB_facade.listFiltered("where o.name='administrator'");
    		System.out.print(this.getClass().getName()+"> USER="+usersList.get(0).getLogin()+" / ROLE="+rolesList.get(0).getName());	
     
    		userEJB_facade.addRoleToUser(rolesList.get(0), usersList.get(0));
    Ce code est situé dans le constructeur du bean session stateful. Quand un client se connecte au module Web (via le navigateur), la servlet est instanciée. Dans chaque session HTTP, le bean privateEJB est injecté.

    Pour les tests (actuellement), lors de l'instanciation du bean privateEJB, je crée le user "admin" et le role "administrator": aucun problème (dans la bd, j'ai tout ce qu'il faut, y compris une table "role_user" contenant (enfin, ne contenant encore rien) les liens entre user et role.

    La méthode "addRoleToUser" est la pour pour lié ces 2 entités. Seulement voilà, j'ai l'erreur de "lazy" cité plus haut. J'ai trouvé pourquoi: dans la facade utilisateur (dans la méthode "addRoleToUser"), je récupère 2 beans entités. Ceux-ci sont considéré comme "non attaché" ce qui pose donc le problème de "lazy". Pour tester, j'ai ajouter cette ligne dans la méthode d'ajout d'un role:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    user=findById(user.getId());	//re-attach user
    AVANT le:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    user.getRoles().add(role);	//add 1 role to the user
    de manière à re-attacher le bean entité ... L'erreur est passé ... enfin non, puisque j'ai le meme souci avec le bean entité "role" passé à la méthode:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    02:07:30,991 WARN  [arjLoggerI18N] [com.arjuna.ats.arjuna.coordinator.TwoPhaseCoordinator_2] TwoPhaseCoordinator.beforeCompletion - failed for com.arjuna.ats.internal.jta.resources.arjunacore.SynchronizationImple@1a46497
    javax.persistence.PersistenceException: org.hibernate.PersistentObjectException: detached entity passed to persist: be.loopx.pixmania.ejb.entity.Role


    Alors voilà, je me rend compte de ceci: je ne peux pas faire un "findById" sur chaque entité dans la facade utilisateur (userEJB_facade), logique (regardez le schéma ci-dessous



    Il m'est impensable de faire l'injection de la facade "role" dans la facade "user"! Donc, le "truc" de l'ajout de la ligne permettant de ratacher le bean entité "user" dans la facade utilisateur est donc à annuler. Il faut que cela se passe AVANT l'appel à la facade!


    J'essaie donc de modifier le bean privateEJB (son constructeur) de manière à ce qu'il soit ainsi:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    //bind administrator to admin
    		usersList=userEJB_facade.listFiltered("where o.login='admin'");
    		rolesList=roleEJB_facade.listFiltered("where o.name='administrator'");
    		System.out.print(this.getClass().getName()+"> USER="+usersList.get(0).getLogin()+" / ROLE="+rolesList.get(0).getName());		
     
    		User user=userEJB_facade.findById(usersList.get(0).getId());
    		//userEJB_facade.addRoleToUser(rolesList.get(0), usersList.get(0));
    		userEJB_facade.addRoleToUser(rolesList.get(0), user);
    en conclusion, avant l'appel à "addRoleToUser", j'essaie de re-attacher le user. J'ai plusieurs question à ce sujet:
    - pourquoi est-ce que la méthode de recherche (avec du code EJBQL) n'a t'elle pas attaché le bean entité USER et ROLE ??
    - pourquoi est-ce que un "findById" juste avant la facade ne fonctionne pas ?

    Parce que le problème est bien la: impossible d'attacher le bean USER (trouvé avec la requette login=admin) AVANT l'appel à la méthode "addRoleToUser". Je bloque, pour tout vous dire, ca fait 1 semaine que je me casse la tête, et rien n'avance. Je pense que j'ai un problème de logique dans le développement ou alors, un problème de "relation" entre bean.

    Je précise que l'erreur (après avoir ajouté le findbyid du user dans le constructeur du bean privateEJB) est exactement la meme que au tout début (donc, le findbyid placé dans privateEJB ne fonctionne pas, alors que si je l'appel quand je suis dans la facade, cela fonctionne).


    Voilà, je suis perdu, je pense que je n'y arriverais jamais sans une petite aide de votre part. Donc, je vous remercie d'avance de me lire.

    EDIT: j'ai d'autre question:
    - qu'elle est la méthode "correct" pour attaché un bean ? (findById ?)
    - est-ce que la méthode utilisée pour "lier" 2 beans entité est correct ?
    - un ptit tuto peut etre, avec exemple parce que, je bloque...

    EDIT2: voici une mini partie des logs, pour ceux que ca intéresse ...
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    02:49:12,031 INFO  [[/web_base]] be.loopx.pixmania.servlet.ControlServlet> All context have been initialized
    02:49:12,062 INFO  [STDOUT] be.loopx.pixmania.ejb.session.PrivateBean> All context have been initialized
    02:49:12,246 INFO  [STDOUT] be.loopx.pixmania.ejb.session.PrivateBean> USER=admin / ROLE=administrator
    actuellement, après ces logs, j'ai les erreurs cité plus haut

  3. #3
    Membre du Club
    Profil pro
    Inscrit en
    Février 2007
    Messages
    64
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations forums :
    Inscription : Février 2007
    Messages : 64
    Points : 54
    Points
    54
    Par défaut
    Merci mille fois pour les explications, je comprend mieux pourquoi l'erreur de Lazy est lancée .

    Seul problème: je n'ai qu'un seul bean stateful, tout les autres sont stateless (le seul stateful est un simple bean session sans entitymanager injecté). Donc, la première solution ne pourra fonctionner.


    Je pense que je vais essayer de mettre en oeuvre la 2ème solution. Il me semble que l'on peu aussi faire un appel à la méthode "size()" de la liste présente dans l'entity User: cela aurait pour effet de récuperer la liste de role qui sont associé au user. Enfin, je sais pas si c'est vraiment pareil.

    Dans tout les cas, merci, je teste ca ce soir

    EDIT:
    Remarque: si tu restes en entityManager TRANSACTION, l'objet u qui sera retourné par ta facade contiendra la collection de Role mais restera détaché du contexte (merge obligatoire dans addRoleToUser)
    Dans mon cas, je vais rester en TRANSACTION (mode par défaut), mais dans ce cas, j'espère que je vais pouvoir utiliser addRoleToUser parce que si User est détaché, comment dois-je m'y prendre ?
    - addRoleToUser récupère un User et un Role (tout deux serait alors détaché )
    - avant de faire le getRoles.add(role), je devrais faire un "merge(user)" et/ou "merge(role) ???
    - puis après, je fais l'ajout (pour cela, doit-je ajouter le role à l'utilisateur et l'utilisateur au role, ou un simple ajout du role à l'utilisateur est suffisant ?
    - après, je refait un merge je suppose ?

    Bah, jvais tester en tout cas, merci mille fois pour la théorie

    EDIT2: voici une très bonne documentation (je suis entrain de la lire, suis tjs au début tellement que c'est complet :p)
    http://pagesperso-orange.fr/emmanuel...eanEntite.html

  4. #4
    Membre du Club
    Profil pro
    Inscrit en
    Février 2007
    Messages
    64
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations forums :
    Inscription : Février 2007
    Messages : 64
    Points : 54
    Points
    54
    Par défaut
    Bonsoir,

    Super, j'ai trouvé la solution

    Je vous montre la solution qui consiste à retoucher la fonction "addRoleToUser":
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    	public void addRoleToUser(Role role, User user) {
    		role=em.merge(role);
    		user=em.merge(user);
     
    		user.getRoles().add(role);	//add 1 role to the user		
    		role.getUsers().add(user);	//add 1 user to the role
    	}
    Donc en gros, le em.find, c'est pas vraiment ce qu'il faut... Il faut faire un merge de l'objet pour le rattacher (et surtout, surtout, pas oublié de le récupérer : user=em.merge...). J'ai du le faire pour role aussi (en toute logique).

    Dans ma table (dans mysql), j'ai ceci:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    mysql> select * from role_user;
    +----------+----------+
    | roles_id | users_id |
    +----------+----------+
    |        1 |        2 |
    +----------+----------+
    1 row in set (0.00 sec)
    seul hic, après re-exécution du code (donc, addRoleToUser), je me serais attendu à une exeption (genre, violation de contrainte) ou à rien de spécial ... mais pas à cela! :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    mysql> select * from role_user;
    +----------+----------+
    | roles_id | users_id |
    +----------+----------+
    |        1 |        2 |
    |        1 |        2 |
    +----------+----------+
    2 rows in set (0.00 sec)
    Donc voilà, j'ai encore 2 questions :
    - comment préciser le nom de la table (automatiquement créée) faisant office de jointure ? (le nom "role_user", je le trouve à l'envers ... j'aimerais bien y mettre "user_role" ... sais pas si c'est dans les anotation ManyToMany que je me suis trompé ...) ???
    - que dois-je faire pour ne pas avoir 2 tuples identiques dans la table de jointure ???


    Je suis entrain de lire le liens que j'ai posté tout à l'heure... Ca m'a appris énormément, et j'en suis qu'a la moitié, peut etre découvrirais-je cela par moi meme

    EDIT: voici la description de la table de jointure, ca peut aider
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    mysql> describe role_user;
    +----------+---------+------+-----+---------+-------+
    | Field    | Type    | Null | Key | Default | Extra |
    +----------+---------+------+-----+---------+-------+
    | roles_id | int(11) | NO   | MUL |         |       |
    | users_id | int(11) | NO   | MUL |         |       |
    +----------+---------+------+-----+---------+-------+
    J'aurais imaginé que le "MUL" signifiait MULTI => clé primaire composite... mais je n'ai encore jamais vu 2 clé primaire identique dans une meme table ...

  5. #5
    Candidat au Club
    Inscrit en
    Janvier 2008
    Messages
    5
    Détails du profil
    Informations forums :
    Inscription : Janvier 2008
    Messages : 5
    Points : 2
    Points
    2
    Par défaut
    salut,

    personnelement je ne connais pas assez bien la techno que tu utilise, donc sur le code je peux pas trop aider (héhé, moi aussi je galère), par contre à titre d'info, pourrais tu afficher ton code SQL de creation de table ?

  6. #6
    Membre du Club
    Profil pro
    Inscrit en
    Février 2007
    Messages
    64
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations forums :
    Inscription : Février 2007
    Messages : 64
    Points : 54
    Points
    54
    Par défaut
    Ca, je n'ai pas, c'est Hibernate qui doit gérer ^^


    La, j'ai changé quelques truc (essayé de mettre un unique sur les 2 colonnes, histoire de faire une clé primaire composite, mais je pense que ca n'a pas fonctionné

    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
    	@ManyToMany(cascade={CascadeType.ALL})
    	@JoinTable(name="USER_ROLE", 
    			uniqueConstraints={@UniqueConstraint(columnNames="user_id"), @UniqueConstraint(columnNames="role_id")},
    			joinColumns=@JoinColumn(name="user_id", referencedColumnName="id"),
    			inverseJoinColumns=
    				@JoinColumn(name="role_id", referencedColumnName="id"))
     
    et dans la Bd, j'ai maintenant ceci :?
    mysql> describe USER_ROLE;
    +---------+---------+------+-----+---------+-------+
    | Field   | Type    | Null | Key | Default | Extra |
    +---------+---------+------+-----+---------+-------+
    | user_id | int(11) | NO   | UNI |         |       |
    | role_id | int(11) | NO   | PRI |         |       |
    +---------+---------+------+-----+---------+-------+
    2 rows in set (0.00 sec)
    Donc, j'y comprend rien ...

    Je sais pas si, normalement, la table doit avoir (table USER_ROLE) automatiquement une clé primaire composite, ou si il faut la faire sois meme (en sachant que la table, c'est lui qui la crée, je n'ai aucun entité mappé dessus).

    Peut etre faut-il utiliser AT Embedabble ... ou truc du style

Discussions similaires

  1. Réponses: 4
    Dernier message: 15/02/2007, 11h06
  2. Count sur une propriété d'un bean entité
    Par dmetzler dans le forum JSF
    Réponses: 11
    Dernier message: 14/02/2007, 22h35
  3. problème avec bean:define
    Par sissi25 dans le forum Struts 1
    Réponses: 4
    Dernier message: 10/01/2007, 11h23
  4. Problème affichage bean
    Par kokumbo dans le forum Struts 1
    Réponses: 8
    Dernier message: 17/10/2006, 21h43
  5. [Debutant] Bean entité BMP - problème JNDI
    Par Tanahjampea dans le forum Tomcat et TomEE
    Réponses: 2
    Dernier message: 17/01/2006, 10h00

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