82 votes

erreur "detached entity passed to persist" avec le code JPA/EJB

J'essaie d'exécuter ce code JPA/EJB de base :

public static void main(String[] args){
         UserBean user = new UserBean();
         user.setId(1);
         user.setUserName("name1");
         user.setPassword("passwd1");
         em.persist(user);
  }

Je reçois cette erreur :

javax.ejb.EJBException: javax.persistence.PersistenceException: org.hibernate.PersistentObjectException: detached entity passed to persist: com.JPA.Database

Des idées ?

J'ai cherché sur internet et la raison que j'ai trouvée était :

Cela était dû à la façon dont vous avez créé les objets, c'est-à-dire si vous avez défini la propriété ID de façon explicite. La suppression de l'affectation de l'ID l'a réglé.

Mais je n'ai pas compris, que dois-je modifier pour que le code fonctionne ?

135voto

L'erreur se produit parce que l'ID de l'objet est fixé. Hibernate fait la distinction entre les objets transitoires et les objets détachés et persist ne fonctionne qu'avec les objets transitoires. Si persist conclut que l'objet est détaché (ce qui sera le cas puisque l'ID est défini), il renverra l'erreur "detached object passed to persist". Vous pouvez trouver plus de détails ici et ici .

Toutefois, cela ne s'applique que si vous avez spécifié que la clé primaire devait être générée automatiquement : si le champ est configuré pour être toujours défini manuellement, alors votre code fonctionne.

0 votes

Est-ce que je suis techniquement correct si je dis que j'utilise JPA et non Hibernate et que la déclaration ci-dessus ne devrait pas s'appliquer ? Je suis novice en matière de JPA (depuis 3 ans pour être précis :P).

0 votes

La Javadoc JPA de Sun ( java.sun.com/javaee/5/docs/api/javax/persistence/ ) et celui de Toplink sont exactement les mêmes et suggèrent que vous avez techniquement raison. Cependant, tout se résume à ce que la spécification dit que persist() devrait se comporter et malheureusement, je ne sais pas ce que c'est.

0 votes

Cette solution a fonctionné pour moi. Je faisais persister un objet, en gardant l'ID stocké quelque part. Je voulais ensuite écraser cet objet existant avec une nouvelle valeur, j'ai donc créé l'objet, recopié l'ID, et ça a explosé quand j'ai essayé de sauvegarder. Finalement, j'ai dû requêter la base de données (findById), effectuer les modifications, puis persister. que objet.

50voto

zawhtut Points 3423

ERD

Disons que vous avez deux entités Album et Photo . L'album contient de nombreuses photos, il s'agit donc d'une relation de type "un à plusieurs".

Classe d'album

@Entity
public class Album {
    @Id
    @GeneratedValue(strategy=GenerationType.AUTO)
    Integer albumId;

    String albumName;

    @OneToMany(targetEntity=Photo.class,mappedBy="album",cascade={CascadeType.ALL},orphanRemoval=true)
    Set<Photo> photos = new HashSet<Photo>();
}

Classe photo

@Entity
public class Photo{
    @Id
    @GeneratedValue(strategy=GenerationType.AUTO)
    Integer photo_id;

    String photoName;

    @ManyToOne(targetEntity=Album.class)
    @JoinColumn(name="album_id")
    Album album;

}

Ce que vous devez faire avant de persister ou de fusionner est de définir la référence de l'album dans chaque photo.

        Album myAlbum = new Album();
        Photo photo1 = new Photo();
        Photo photo2 = new Photo();

        photo1.setAlbum(myAlbum);
        photo2.setAlbum(myAlbum);       

C'est ainsi que l'on attache l'entité liée avant de persister ou de fusionner.

2 votes

Si vous utilisez des génériques, il n'est pas nécessaire d'utiliser "targetEntity=Photo.class".

0 votes

Bonjour, après avoir défini l'objet album sur photo1 et photo2... quel objet devons-nous utiliser pour sauvegarder la liste des photos ou l'album ?

25voto

Ammar Bozorgvar Points 453

Supprimer

user.setId(1);

parce que c'est une génération automatique sur la base de données, et continuer avec la commande persistante.

12voto

zengr Points 14506

J'ai eu la réponse, je me servais :

em.persist(user);

J'ai utilisé merge à la place de persist :

em.merge(user);

Mais aucune idée de la raison pour laquelle il n'a pas fonctionné :(

11 votes

Ce n'est pas la solution !

1 votes

Je sais, mais cela a fonctionné pour moi. y a-t-il une autre réponse ici qui a fonctionné pour vous ? si oui, alors je serai plus qu'heureux de la sélectionner.

4 votes

Cela a fonctionné parce que votre objet a été détaché de la session Hibernate ou l'objet est transitoire mais Hibernate le voit comme détaché parce que vous avez déclaré la clé primaire. En utilisant la fusion, vous attachez à nouveau l'objet à la session, ce qui vous permet de mettre à jour les objets de votre base de données ; voir : docs.jboss.org/hibernate/core/3.3/reference/en/html/

11voto

Si vous utilisez pour générer le id = GenerationType.AUTO dans votre entité.

Remplace user.setId (1) par user.setId (null) et le problème est résolu.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X