"detached entity passed to persist error" with JPA/EJB code
Asked Answered
D

10

83

I am trying to run this basic JPA/EJB code:

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

I get this error:

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

Any ideas?

I search on the internet and the reason I found was:

This was caused by how you created the objects, i.e. If you set the ID property explicitly. Removing ID assignment fixed it.

But I didn't get it, what will I have to modify to get the code working?

Donielle answered 14/3, 2010 at 8:25 Comment(0)
R
51

ERD

Let's say you have two entities Album and Photo. Album contains many photos, so it's a one to many relationship.

Album class

@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>();
}

Photo class

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

    String photoName;

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

}

What you have to do before persist or merge is to set the Album reference in each photos.

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

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

That is how to attach the related entity before you persist or merge.

Ranunculus answered 5/2, 2011 at 5:0 Comment(2)
If you use generics, there is no need of using "targetEntity=Photo.class"Footed
hi, after setting album object to photo1 nad photo2... what object we have to save list of Photos or Album?Goosy
S
140

The error occurs because the object's ID is set. Hibernate distinguishes between transient and detached objects and persist works only with transient objects. If persist concludes the object is detached (which it will because the ID is set), it will return the "detached object passed to persist" error. You can find more details here and here.

However, this only applies if you have specified the primary key to be auto-generated: if the field is configured to always be set manually, then your code works.

Steinbach answered 14/3, 2010 at 11:44 Comment(3)
Will I be technically right when I say, I am using JPA and not Hibernate so, that above statement should not apply right? I am newbie in JPA (3 ays to be precise :P)Donielle
Sun's JPA Javadoc (java.sun.com/javaee/5/docs/api/javax/persistence/…) and that of Toplink are exactly the same and suggest you are technically right. However, it really boils down to what the specification says persist() should behave like and sadly, I don't know what that is.Steinbach
This solution worked for me. I was persisting an object, keeping the ID stored somewhere. I then want to overwrite that existing object with a new value, so I created the object, copied the ID back in, and it blew up when I tried to save. In the end, I had to requery the DB (findById), make the changes, and then persist that object.Tenerife
R
51

ERD

Let's say you have two entities Album and Photo. Album contains many photos, so it's a one to many relationship.

Album class

@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>();
}

Photo class

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

    String photoName;

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

}

What you have to do before persist or merge is to set the Album reference in each photos.

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

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

That is how to attach the related entity before you persist or merge.

Ranunculus answered 5/2, 2011 at 5:0 Comment(2)
If you use generics, there is no need of using "targetEntity=Photo.class"Footed
hi, after setting album object to photo1 nad photo2... what object we have to save list of Photos or Album?Goosy
P
25

remove

user.setId(1);

because it is auto generate on the DB, and continue with persist command.

Peper answered 20/4, 2011 at 7:27 Comment(0)
D
14

I got the answer, I was using:

em.persist(user);

I used merge in place of persist:

em.merge(user);

But no idea, why persist didn't work. :(

Donielle answered 14/3, 2010 at 9:7 Comment(3)
this is not the solution !Peper
i know, but this worked for me. any other answer here which worked for you? if yes, then i will be more than happy to select it.Donielle
It worked because your object was detached from the hibernate session or the object is transient but hibernate sees it as detached because you got the primary key declared, With using merge you attach the object tot he session again this enables you to update objects in your database; see: docs.jboss.org/hibernate/core/3.3/reference/en/html/…Brandy
S
11

if you use to generate the id = GenerationType.AUTO strategy in your entity.

Replaces user.setId (1) by user.setId (null), and the problem is solved.

Sylvan answered 24/8, 2012 at 4:49 Comment(0)
S
7

Here .persist() only will insert the record.If we use .merge() it will check is there any record exist with the current ID, If it exists, it will update otherwise it will insert a new record.

Shoffner answered 16/7, 2012 at 14:41 Comment(1)
It costed me a ton of time until I got your answer. Thank you very much!Sension
T
5

I know its kind of too late and proly every one got the answer. But little bit more to add to this: when GenerateType is set, persist() on an object is expected to get an id generated.

If there is a value set to the Id by user already, hibernate treats it as saved record and so it is treated as detached.

if the id is null - in this situation a null pointer exception is raised when the type is AUTO or IDENTITY etc unless the id is generated from a table or a sequece etc.

design: this happens when the table has a bean property as primary key. GenerateType must be set only when an id is autogenerated. remove this and the insert should work with the user specified id. (it is a bad design to have a property mapped to primary key field)

Tini answered 5/7, 2012 at 21:8 Comment(0)
E
3

If you set id in your database to be primary key and autoincrement, then this line of code is wrong:

user.setId(1);

Try with this:

public static void main(String[] args){
         UserBean user = new UserBean();
         user.setUserName("name1");
         user.setPassword("passwd1");
         em.persist(user);
  }
Elastomer answered 28/2, 2016 at 11:47 Comment(1)
I tried that and I know getting this error: detached entity passed to persistQuickly
D
2

I had this problem and it was caused by the second level cache:

  1. I persisted an entity using hibernate
  2. Then I deleted the row created from a separate process that didn't interact with the second level cache
  3. I persisted another entity with the same identifier (my identifier values are not auto-generated)

Hence, because the cache wasn't invalidated, hibernate assumed that it was dealing with a detached instance of the same entity.

Depoliti answered 11/3, 2011 at 15:55 Comment(0)
W
0

You can assign ID and then persist an entity, if, for example, your ID is represented by email of a user. But, to make it work, you need to make sure that your ID field doesn't have @GeneratedValue set.

For example, this code will raise an exception if you have this Entity with the email ID field and @GeneratedValue set:

public class UserEntity {
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Id
    @Column(name = "email")
    private String email;

    ...
}

and try to persist such an object:

UserEntity user = new UserEntity();
user.setEmail(email);
entityManager.getTransaction().begin();
entityManager.persist(user);
entityManager.getTransaction().commit();

so, in order to make it work, you need to remove the @GeneratedValue, but keep the @ID:

public class UserEntity {
    @Id
    @Column(name = "email")
    private String email;

    ...
}
Wrongful answered 19/8, 2023 at 15:1 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.