使用JPA/EJB代码将"分离的实体传递给持久性错误"

zen*_*ngr 80 java jpa ejb-3.0

我正在尝试运行这个基本的JPA/EJB代码:

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

我收到此错误:

javax.ejb.EJBException: javax.persistence.PersistenceException: org.hibernate.PersistentObjectException: detached entity passed to persist: com.JPA.Database
Run Code Online (Sandbox Code Playgroud)

有任何想法吗?

我在互联网上搜索,我找到的原因是:

这是由您创建对象的方式引起的,即如果您明确设置了ID属性.删除ID分配修复了它.

但我没有得到它,我需要修改什么来使代码工作?

Tom*_*vic 126

发生错误是因为设置了对象的ID.Hibernate区分瞬态和分离对象,persist仅适用于瞬态对象.如果persist结束对象是分离的(因为ID已设置),它将返回"传递给持久化的分离对象"错误.您可以在此处此处找到更多详细信息.

然而,这仅适用于如果您指定的主键是自动生成的:如果该字段设置为始终手动设置,那么你的代码工作.


zaw*_*tut 49

ERD

比方说,你有两个实体AlbumPhoto.相册包含许多照片,因此它是一对多的关系.

专辑类

@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>();
}
Run Code Online (Sandbox Code Playgroud)

照片课

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

    String photoName;

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

}
Run Code Online (Sandbox Code Playgroud)

在保留或合并之前您需要做的是在每张照片中设置"影集"参考.

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

        photo1.setAlbum(myAlbum);
        photo2.setAlbum(myAlbum);       
Run Code Online (Sandbox Code Playgroud)

这是在持久化或合并之前附加相关实体的方法.

  • 如果使用泛型,则无需使用“ targetEntity = Photo.class” (2认同)

Amm*_*var 22

去掉

user.setId(1);
Run Code Online (Sandbox Code Playgroud)

因为它是在DB上自动生成的,并继续使用persist命令.


zen*_*ngr 12

我得到了答案,我正在使用:

em.persist(user);
Run Code Online (Sandbox Code Playgroud)

我使用merge代替persist:

em.merge(user);
Run Code Online (Sandbox Code Playgroud)

但不知道,为什么坚持不起作用.:(

  • 这不是解决方案! (11认同)
  • 它的工作原理是你的对象与hibernate会话分离或者对象是暂时的,但是hibernate认为它是分离的,因为你声明了主键,使用merge你再次将对象附加到会话中,这使你可以更新数据库中的对象; 请参阅:http://docs.jboss.org/hibernate/core/3.3/reference/en/html/objectstate.html#objectstate-detached (4认同)

小智 9

如果您用于id = GenerationType.AUTO在您的实体中生成策略.

替换user.setId (1)user.setId (null),问题就解决了.


小智 5

我知道它太迟了,而且每个人都得到答案.但要添加一点:当GenerateType设置时,对象上的persist()应该生成一个id.

如果用户已将值设置为Id,则hibernate会将其视为已保存的记录,因此将其视为已分离.

如果id为null - 在这种情况下,当类型为AUTO或IDENTITY等时引发空指针异常,除非id是从表或sequece等生成的.

设计:当表具有bean属性作为主键时,会发生这种情况.只有在自动生成id时才必须设置GenerateType.删除它,插入应该与用户指定的ID一起使用.(将属性映射到主键字段是一种糟糕的设计)


PSR*_*PSR 5

在这里.persist()仅会插入记录。如果我们使用.merge()它将检查是否存在具有当前ID的记录,如果存在,它将更新,否则将插入新记录。