web-dev-qa-db-fra.com

"entité détachée transmise à l'erreur persistante" avec 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 pour laquelle j'ai trouvé était: 

Cela était dû à la manière dont vous avez créé les objets, c’est-à-dire si vous définissez explicitement la propriété ID. La suppression de l'attribution d'identifiant a résolu le problème.

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

72
zengr

ERD

Supposons que vous avez deux entités Album et Photo. L'album contient de nombreuses photos, il s'agit donc d'une relation 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>();
}

Cours de 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;

}

Avant de continuer ou de fusionner, vous devez 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 comment attacher l'entité associée avant de persister ou de fusionner.

50
zawhtut

L'erreur se produit parce que l'ID de l'objet est défini. Hibernate distingue les objets transitoires des objets détachés et persist fonctionne uniquement avec les objets transitoires. Si persist conclut que l'objet est détaché (ce qui sera le cas parce que l'ID est défini), l'erreur "erreur de retour de l'objet détaché est renvoyée". Vous pouvez trouver plus de détails ici et ici .

Cependant, ceci ne s'applique que si vous avez spécifié la clé primaire à générer automatiquement: si le champ est configuré pour toujours être défini manuellement, votre code fonctionne.

121

retirer 

user.setId(1);

car il est auto-généré sur la base de données, et continue avec la commande persist.

22
Ammar Bozorgvar

J'ai eu la réponse, j'utilisais:

em.persist(user);

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

em.merge(user);

Mais aucune idée, pourquoi persister n'a pas fonctionné. :(

12
zengr

si vous utilisez pour générer la stratégie id = GenerationType.AUTO dans votre entité.

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

9
Sergio Ordóñez

Je sais que c'est trop tard et que tout le monde a la réponse. Mais un petit peu plus à ajouter à cela: lorsque GenerateType est défini, persist () sur un objet devrait obtenir un identifiant généré.

Si une valeur est déjà définie par l'utilisateur par l'id, hibernate la traite comme un enregistrement sauvegardé et est donc traitée comme détachée.

si l'id est null - dans cette situation, une exception de pointeur null est déclenchée lorsque le type est AUTO ou IDENTITY, etc. sauf si l'ID est généré à partir d'une table ou d'une séquence, etc.

design: cela se produit lorsque la table a une propriété de bean en tant que clé primaire . GenerateType doit être défini uniquement lorsqu'un identifiant est généré automatiquement . supprimez-le et l'insertion doit fonctionner avec l'ID spécifié par l'utilisateur .. est une mauvaise conception pour avoir une propriété mappée sur le champ de clé primaire)

5
haripriya

Ici .persist () seulement insérera l'enregistrement.Si nous utilisons .merge () il va vérifier s'il existe un enregistrement avec l'ID actuel, s'il existe, il se mettra à jour sinon un nouveau disque.

4
PSR

Si vous définissez id dans votre base de données comme clé primaire et auto-incrémentation, cette ligne de code est incorrecte: 

user.setId(1);

Essayez avec ceci:

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

J'ai eu ce problème et il a été causé par le cache de second niveau:

  1. J'ai persisté une entité utilisant Hibernate
  2. Ensuite, j'ai supprimé la ligne créée à partir d'un processus distinct qui n'interagissait pas avec le cache de second niveau.
  3. J'ai persisté une autre entité avec le même identifiant (mes valeurs d'identifiant ne sont pas générées automatiquement)

Ainsi, le cache n’ayant pas été invalidé, hibernate a supposé qu’il s’agissait d’une instance détachée de la même entité.

2
hertzsprung

Une autre raison d'erreur que votre objet d'entité n'implémente pas l'interface Serializable

@Entity
@Table(name = OddInstance.objectName, uniqueConstraints = @UniqueConstraint(columnNames = {"alias"}))
@NamedQueries({
    @NamedQuery(name=OddInstance.findByAlias,
            query="from OddInstance where alias = :alias"),
    @NamedQuery(name=OddInstance.findAll,
            query="from OddInstance")
})
public class OddInstance implements Serializable {
    // ...
}
0
Evgeny Lebedev