首页 文章

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

提问于
浏览
72

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

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

我收到此错误:

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

有任何想法吗?

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

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

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

10 回答

  • 5

    ERD

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

    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;
    
    }
    

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

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

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

  • 2

    发生错误是因为设置了对象的ID . Hibernate区分瞬态和分离对象, persist 仅适用于瞬态对象 . 如果 persist 结束对象已分离(因为ID已设置),则会返回"detached object passed to persist"错误 . 您可以找到更多详细信息herehere .

    但是,这仅适用于您已指定要自动生成的主键的情况:如果该字段配置为始终手动设置,则代码可以正常工作 .

  • 0

    去掉

    user.setId(1);
    

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

  • 4

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

    em.persist(user);
    

    我使用merge代替persist:

    em.merge(user);
    

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

  • 12

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

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

  • 120

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

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

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

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

  • 2

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

  • 49

    我有这个问题,它是由二级缓存引起的:

    • 我使用hibernate持久化了一个实体

    • 然后我删除了从不与二级缓存交互的单独进程创建的行

    • 我持有另一个具有相同标识符的实体(我的标识符值不是自动生成的)

    因此,因为缓存没有失效,所以hibernate假定它正在处理同一实体的分离实例 .

  • 22

    如果您将数据库中的id设置为主键和自动增量,那么这行代码是错误的:

    user.setId(1);
    

    试试这个:

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

    实体对象未实现 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 {
        // ...
    }
    

相关问题