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

Java EE Discussion :

Problème EJB instantiation : "un objet de même identifiant existe déjà"


Sujet :

Java EE

  1. #1
    Membre à l'essai
    Homme Profil pro
    Étudiant
    Inscrit en
    Juin 2015
    Messages
    18
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 53
    Localisation : France, Seine Saint Denis (Île de France)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Juin 2015
    Messages : 18
    Points : 15
    Points
    15
    Par défaut Problème EJB instantiation : "un objet de même identifiant existe déjà"
    Bonjour (ou Bonsoir)

    JBoss n'est pas content quand j'appelle la méthode test1() de mon bean SessionTests :

    21:02:47,474 ERROR [org.jboss.as.ejb3.invocation] (http-/127.0.0.1:8080-1) JBAS014134: L'invocation EJB a échoué sur le composant SessionTests pour la méthode public abstract java.lang.String org.gfarny.ejb3.SessionTestsRemote.test1() throws java.text.ParseException: javax.ejb.EJBException: javax.persistence.EntityExistsException: a different object with the same identifier value was already associated with the session: [org.gfarny.ejb3.EntityBudyPhone#EntityBudyPhone[0,0]]

    "...with the same identifier value..." : voilà le problème.



    Bean de la méthode test1() censée faire une instantiation frauduleuse :
    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
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    package org.gfarny.ejb3;
     
    import java.text.ParseException;
    import java.text.SimpleDateFormat;
     
    import javax.annotation.PostConstruct;
    import javax.annotation.PreDestroy;
    import javax.ejb.PostActivate;
    import javax.ejb.PrePassivate;
    import javax.ejb.Remote;
    import javax.ejb.Stateful;
    import javax.persistence.EntityManager;
    import javax.persistence.EntityManagerFactory;
    import javax.persistence.EntityTransaction;
    import javax.persistence.Persistence;
     
    @Stateful
    @Remote(SessionTestsRemote.class)
    public class SessionTests implements SessionTestsRemote {
    	private static EntityManagerFactory emf;
    	private static EntityManager em;
     
    	public SessionTests () {}
     
    	@Override
    	public EntityManager getEntityManager() {
    		return em;
    	}
     
    	@Override
    	public String test1 () throws ParseException {
    		StringBuffer buf = new StringBuffer();
    		EntityTransaction tx = em.getTransaction();
    		tx.begin();
     
    		EntityBudy b1 = new EntityBudy(
    					"Martin", "Paul", new SimpleDateFormat("dd/MM/yy").parse("31/01/2000"));
    		EntityBudy b2 = new EntityBudy(
    				"Jacqueline", "Duchemin", new SimpleDateFormat("dd/MM/yy").parse("12/02/1980"));
    		EntityPhone p1 = new EntityPhone("0654512961");
    		EntityBudyPhone bp1 = new EntityBudyPhone(b1,p1);
    		EntityBudyPhone bp2 = new EntityBudyPhone(b2,p1);
    		//b1.addEntityBudyPhone(p1);
    		//p1.addEntityBudyPhone(b2);
    		em.persist(b1);
    		em.persist(b2);
    		em.persist(p1);
    		em.persist(bp1);
    		em.persist(bp2);
     
    		tx.commit();
     
    		// test purpose
    		for (Object c : em.createQuery("select c from EntityCountry c order by c.code asc").getResultList()) {
    			buf.append(((EntityCountry)c).getCode());
    			buf.append(", ");
    		}
     
    		tx = null;
    		return buf.toString();
    	}
     
    	@PostConstruct
        public void postConstruct()
        {
    		// "jpa" fait reference au <persistence-unit> du fichier persistence.xml
    		emf = Persistence.createEntityManagerFactory("jpa");
    		em = emf.createEntityManager();
        }
     
    	@PreDestroy
        public void preDestroy()
        {
    		em.close();
    		emf.close();
        }
     
    	@PostActivate
        public void postActivate() {}
     
    	@PrePassivate
        public void prePassivate() {}
    }
    Voici le code JSP qui appelle tout ça :
    Code jsp : 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
    <%@ page language="java" contentType="text/html; charset=UTF-8"
        pageEncoding="UTF-8"
        import="java.util.*,javax.ejb.*,javax.rmi.PortableRemoteObject,javax.naming.*,org.gfarny.ejb3.*"%>
    <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
    <html>
    <head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    <title>Insert title here</title>
    </head>
    <body>
    <% 
    SessionTestsRemote sessionTestsRemote = null;
    String c_code = request.getParameter("code");
    String c_fullname = request.getParameter("fullname");
    try {
            // JBoss 6 specific
        final Hashtable<String, String> jndiProperties = new Hashtable<String, String>();
        jndiProperties.put(Context.URL_PKG_PREFIXES, "org.jboss.ejb.client.naming");
            
            InitialContext ctx = new InitialContext(jndiProperties);
            
            // initialise le contexte de Tests : ?stateful useless ???
            sessionTestsRemote = (SessionTestsRemote) ctx.lookup(
                    "java:jboss/exported/ejbjpa/ejbjpa.jar/SessionTests!org.gfarny.ejb3.SessionTestsRemote");
            
            // effectue le test1
            sessionTestsRemote.test1();
            
            } catch (Exception e) {
            e.printStackTrace ();
    }
     
    //...
    %>
    <br>
    <%
    // ...
    %>
    </body>
    </html>

    ...une dernière interrogation :
    mon URI JNDI devrait se terminer par "?stateful" quand je fais un lookup, puisque mon bean est stateful,
    et que la doc de JBoss précise bien qu'il faut le faire... or dans la liste de mes noms JNDI l'URI apparaît être sans "?stateful"

    une idée ?

    Merci d'avance !

  2. #2
    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
    on peut voir la définition de tes beans?

  3. #3
    Membre à l'essai
    Homme Profil pro
    Étudiant
    Inscrit en
    Juin 2015
    Messages
    18
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 53
    Localisation : France, Seine Saint Denis (Île de France)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Juin 2015
    Messages : 18
    Points : 15
    Points
    15
    Par défaut beans
    Bien sûr.

    Voilà l'idée : gérer une association many-to-many à l'aide d'une classe associative pointée par deux associations one-to-many

    [ EntityPhone ] <=(1)====(many)=> [ EntityBudyPhone ] <=(many)====(1)=> [ EntityBudy ]

    ci-dessous le code de mes trois beans

    le bean EntityBudyPhone (la classe associative)

    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
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    package org.gfarny.ejb3;
     
    import java.io.Serializable;
     
    import javax.persistence.CascadeType;
    import javax.persistence.Column;
    import javax.persistence.Embeddable;
    import javax.persistence.EmbeddedId;
    import javax.persistence.Entity;
    import javax.persistence.GeneratedValue;
    import javax.persistence.GenerationType;
    import javax.persistence.Id;
    import javax.persistence.JoinColumn;
    import javax.persistence.ManyToOne;
    import javax.persistence.OneToOne;
    import javax.persistence.Table;
    import javax.persistence.UniqueConstraint;
    import javax.ejb.CreateException;
     
    @Entity
    @Table(name="phone_rel_bud", uniqueConstraints = @UniqueConstraint(columnNames = {"ph_fk","budy_fk"}))
    public class EntityBudyPhone implements Serializable {
     
    	private static final long serialVersionUID = 4037447988458724371L;
     
    	@Embeddable
    	public static class Id implements Serializable {
    		private static final long serialVersionUID = -9040939392333356524L;
     
    		@Column(name="budy_fk", nullable=false)
    		private int budyFk = 0;
     
    		@Column(name="ph_fk", nullable=false)
    		private int phoneFk = 0;
     
    		public void setBudyFk(int b) {
    			this.budyFk = b;
    		}
     
    		public int getBudyFk() {
    			return budyFk;
    		}
     
    		public void setPhoneFk(int p) {
    			this.phoneFk = p;
    		}
     
    		public int getPhoneFk() {
    			return phoneFk;
    		}
     
    		Id() {}
     
    		Id(int budyFk, int phoneFk) {
    			setBudyFk(budyFk);
    			setPhoneFk(phoneFk);
    		}
     
    		public String toString() {
    			return String.format("EntityBudyPhone[%d,%d]", getBudyFk(), getPhoneFk());
    		}
     
    		public int hashCode() {
    			return this.toString().hashCode();
    		}
     
    		public boolean equals (Object o) {
    	        if (o instanceof Id){
    	        	Id i = (Id) o;
    	        	if (this.budyFk == i.getBudyFk() && this.phoneFk == i.getPhoneFk())
    	        	{
    	        		return true;
    	        	}
    	        }
    	        return false;
    		}
    	}
     
    	@EmbeddedId
    	private Id id;
     
    	// JPA ne doit pas gérer cette clé étrangère (insertable = false, updatable = false)
    	@ManyToOne
    	@JoinColumn(name="budy_fk", insertable=false, updatable=false)
    	private EntityBudy entityBudy;
     
    	// JPA ne doit pas gérer cette clé étrangère (insertable = false, updatable = false)
    	@ManyToOne
    	@JoinColumn(name="ph_fk", insertable=false, updatable=false)
    	private EntityPhone entityPhone;
     
    	public Id getId() {
    		return id;
    	}
     
    	public void setEntityBudy(EntityBudy eb) {
    		entityBudy = eb;
    	}
     
    	public EntityBudy getEntityBudy() {
    		return entityBudy;
    	}
     
    	public void setEntityPhone(EntityPhone ep) {
    		entityPhone = ep;
    	}
     
    	public EntityPhone getEntityPhone() {
    		return entityPhone;
    	}
     
    	public EntityBudyPhone() {}
     
    	public EntityBudyPhone(EntityBudy eb, EntityPhone ep) {
    		id = new Id(eb.getId(), ep.getId());
    		setEntityBudy(eb);
    		setEntityPhone(ep);
    		eb.getEntityBudyPhoneSet().add(this);
    		ep.getEntityBudyPhoneSet().add(this);
    	}
    }
    EntityBudy :

    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
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    package org.gfarny.ejb3;
     
    import java.io.Serializable;
    import java.util.Date;
    import java.util.HashSet;
    import java.util.Set;
     
    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.OneToMany;
    import javax.persistence.Table;
    import javax.persistence.Temporal;
    import javax.persistence.TemporalType;
    import javax.persistence.UniqueConstraint;
     
    @Entity
    @Table(name="budies", uniqueConstraints = @UniqueConstraint(columnNames = {"first","family","born"}))
    public class EntityBudy implements Serializable {
    	private static final long serialVersionUID = 8130381994354278601L;
     
    	@Id
    	@GeneratedValue(strategy=GenerationType.AUTO)
    	@Column(name="id", nullable=false)
    	private int id;
     
    	@Column(name="first", length=30, nullable=false)
    	private String first;
     
    	@Column(name="family", length=30, nullable=false)
    	private String family;
     
    	@Column(name="born")
    	@Temporal(TemporalType.DATE)
    	private Date born;
     
    	@OneToMany(mappedBy="entityBudy", cascade={CascadeType.REMOVE})
    	private Set<EntityBudyPhone> entityBudyPhoneSet = new HashSet<EntityBudyPhone>();
     
    	public int getId() {
    		return id;
    	}
     
    	public void setId(int id) {
    		this.id = id;
    	}
     
    	public String getFirst() {
    		return first;
    	}
     
    	public void setFirst (String f) {
    		this.first = f;
    	}
     
    	public String getFamily() {
    		return family;
    	}
     
    	public void setFamily(String f) {
    		this.family = f;
    	}
     
    	public Date getBorn() { return born; }
     
    	public void setBorn(Date dte) {
    		this.born = dte;
    	}
     
    	public EntityBudy() {}
     
    	public EntityBudy(String fst, String fam) {
    		setFirst(fst);
    		setFamily(fam);
    	}
     
    	public EntityBudy(String fst, String fam, Date dte) {
    		setFirst(fst);
    		setFamily(fam);
    		setBorn(dte);
    	}
     
    	public Set<EntityBudyPhone> getEntityBudyPhoneSet() {
    		return entityBudyPhoneSet;
    	}
     
    	// adding to Set is delegated to EntityBudyPhone.new()
    	public void addEntityBudyPhone(EntityPhone ep) {
    		new EntityBudyPhone(this, ep);
    	}
     
    	public boolean equals(EntityBudy b) {
    		if (this.first == b.getFirst())
    			if (this.family == b.getFamily())
    				if (this.born == b.getBorn())
    					return true;
    		return false;
    	}
    }
    EntityPhone :

    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
    65
    66
    67
    68
    69
    package org.gfarny.ejb3;
     
    import java.io.Serializable;
    import java.util.HashMap;
    import java.util.HashSet;
    import java.util.Map;
    import java.util.Set;
     
    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.JoinTable;
    import javax.persistence.ManyToMany;
    import javax.persistence.MapKey;
    import javax.persistence.OneToMany;
    import javax.persistence.Table;
    import javax.persistence.UniqueConstraint;
    import javax.ejb.CreateException;
     
    @Entity
    @Table(name="phones", uniqueConstraints = @UniqueConstraint(columnNames = "number"))
    public class EntityPhone implements Serializable {
    	private static final long serialVersionUID = -2978404436259062565L;
     
    	@Id
    	@GeneratedValue(strategy=GenerationType.AUTO)
    	@Column(name="id", nullable=false)
    	private int id;
     
    	@Column(name="number", length=30, nullable=false)
    	private String number;
     
    	@OneToMany(mappedBy="entityPhone", cascade={CascadeType.REMOVE})
    	private Set<EntityBudyPhone> entityBudyPhoneSet = new HashSet<EntityBudyPhone>();
     
    	public int getId() {
    		return id;
    	}
     
    	public void setId(int id) {
    		this.id = id;
    	}
     
    	public String getNumber() {
    		return number;
    	}
     
    	public void setNumber(String n) {
    		this.number = n;
    	}
     
    	public EntityPhone() {}
     
    	public EntityPhone(String n) {
    		setNumber(n);
    	}
     
    	public Set<EntityBudyPhone> getEntityBudyPhoneSet() {
    		return entityBudyPhoneSet;
    	}
     
    	// adding to Set is delegated to EntityBudyPhone.new()
    	public void addEntityBudyPhone(EntityBudy eb) {
    		new EntityBudyPhone(eb, this);
    	}
    }
    Merci !

  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
    Ta clé composite et mal réalisée. Les id qu'elle contient sont les id de deux entité, donc au lieu de les déclaré comme int tu devrais les déclaré comme les entités en question:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    		@ManyToOne
    		@Column(name="budy_fk", nullable=false)
    		private EntityBudy budy;
     
    		@ManyToOne
    		@Column(name="ph_fk", nullable=false)
    		private EntityPhone phone;

    Ton code essaie de copier les ids vers ces valeurs à la main dans le constructeur, mais vu que c'est JPA qui gère ces ids (cf la auto generate sur la clé primaire des deux entités), tu ne peux pas savoir exactement si ces ids sont disponibles. En stockant plutot les entité tu laisse jpa faire son travail proprement.

  5. #5
    Membre chevronné
    Avatar de eulbobo
    Homme Profil pro
    Développeur Java
    Inscrit en
    Novembre 2003
    Messages
    786
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 45
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Développeur Java

    Informations forums :
    Inscription : Novembre 2003
    Messages : 786
    Points : 1 993
    Points
    1 993
    Par défaut
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     
    	public boolean equals(EntityBudy b) {
    		if (this.first == b.getFirst())
    			if (this.family == b.getFamily())
    				if (this.born == b.getBorn())
    					return true;
    		return false;
    	}
    Attention, cette méthode n'a pas la bonne signature pour être utilisée par une comparaison d'objets (qui doit être de la forme boolean equals(Object) )
    Et si tu définis equals, il FAUT définir hashCode
    Je ne suis pas mort, j'ai du travail !

Discussions similaires

  1. Problème sauvegarde de plusieurs instanciations d'un même type d'objet
    Par janyoura dans le forum Débuter avec Java
    Réponses: 18
    Dernier message: 27/05/2014, 12h14
  2. Réponses: 6
    Dernier message: 16/02/2013, 12h45
  3. Problème d'instantiation d'objets ?
    Par ddos12 dans le forum Général Python
    Réponses: 3
    Dernier message: 07/07/2010, 18h17
  4. [TTreeView] Problème avec les pointeurs d'objet
    Par BlackWood dans le forum Composants VCL
    Réponses: 2
    Dernier message: 02/07/2004, 14h31
  5. [C#] Problème pour l'appel d'objet...
    Par AntiSAL dans le forum Windows Forms
    Réponses: 2
    Dernier message: 14/06/2004, 09h59

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