持久化H2中的ManyToMany实体抛出异常

时间:2018-05-07 13:02:36

标签: java spring hibernate spring-boot jpa

我有两个实体,其中两个都有彼此的列表。

Class" Post":

@ManyToMany(mappedBy = "posts", cascade=CascadeType.ALL)
private List<Tag> tags;

Class&#34; Tag&#34;:

@ManyToMany(cascade = CascadeType.ALL)
@JoinTable
private List<Post> posts;`

在db中我有&#34; POSTS&#34;表,&#34; TAGS&#34;表和&#34; TAGS_POSTS&#34;对于ManyToMany的关系。数据库中的结构和db中的表都很好。但是当我开始坚持Post Post in Posts表时出现错误。

这是用于向db添加新帖子的代码,相同的代码适用于其他实体,即使对于&#34; Tag&#34;也有ManyToMany的关系。

private EntityManagerFactory emf;

@PersistenceUnit
public void setEmf(EntityManagerFactory emf) {
    this.emf = emf;
}

public Post add(Post post) {
    EntityManager em = emf.createEntityManager();
    em.getTransaction().begin();
    em.persist(post);
    em.getTransaction().commit();
    return post;
}

现在在应用程序开始时,我尝试使用一些虚拟数据填充db进行测试。具有相同代码的每个其他实体都工作正常,除了Post。

这是代码(我尝试没有设置tags属性,将其设置为空ArrayList,并将其设置为db结果中已存在的标记列表是相同的):

 ApplicationContext ac =  SpringApplication.run(PostsPortalApplication.class, args);


 PostsService ps = (PostsService) ac.getBean("postsService");

 Post post = new Post();
 post.setId(j);
 post.setDate(new Date());
 post.setDescription("desc" +  "/" );
 post.setDislikes(5);
 post.setLikes(5);
 post.setLocationLat(5);
 post.setLocationLong(5);
 post.setPhotoUrl("URL" +  "/" + j);
 post.setTitle("Title"  + "/" + j);
 post.setUser(user);
 post.setTags(new ArrayList<>());
 ps.add(post);

这是异常消息(PostsService.java:38是行):em.persist(post);

  

线程中的异常&#34; main&#34; javax.persistence.PersistenceException:org.hibernate.PersistentObjectException:传递给persist的分离实体:jovan.sf_62_2017.postsportal.pojo.Post       在org.hibernate.internal.ExceptionConverterImpl.convert(ExceptionConverterImpl.java:149)       在org.hibernate.internal.ExceptionConverterImpl.convert(ExceptionConverterImpl.java:157)       在org.hibernate.internal.ExceptionConverterImpl.convert(ExceptionConverterImpl.java:164)       在org.hibernate.internal.SessionImpl.firePersist(SessionImpl.java:789)       在org.hibernate.internal.SessionImpl.persist(SessionImpl.java:767)       at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)       at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)       at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)       at java.lang.reflect.Method.invoke(Method.java:498)       在org.springframework.orm.jpa.ExtendedEntityManagerCreator $ ExtendedEntityManagerInvocationHandler.invoke(ExtendedEntityManagerCreator.java:350)       at com.sun.proxy。$ Proxy85.persist(Unknown Source)       在jovan.sf_62_2017.postsportal.services.implementations.PostsService.add(PostsService.java:38)       在jovan.sf_62_2017.postsportal.PostsPortalApplication.main(PostsPortalApplication.java:67)

     

引起:org.hibernate.PersistentObjectException:传递给persist的分离实体:jovan.sf_62_2017.postsportal.pojo.Post       at org.hibernate.event.internal.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:124)       在org.hibernate.event.internal.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:58)       在org.hibernate.internal.SessionImpl.firePersist(SessionImpl.java:782)       ... 9更多

2 个答案:

答案 0 :(得分:1)

首先请改变:

cascade=CascadeType.ALL

到:

cascade = {CascadeType.PERSIST, CascadeType.MERGE}

因为CascadeType.REMOVE在使用CascadeType.ALL时会自动继承,但实体删除不仅应用于链接表,还应用于关联的另一端。(see hear

所以试试这段代码:

    @ManyToMany(mappedBy = "posts", 
            cascade = {CascadeType.PERSIST, CascadeType.MERGE})
    private List<Tag> tags;




@ManyToMany(cascade = 
        {CascadeType.PERSIST, CascadeType.MERGE})
    @JoinTable(name = "post_tag",
        joinColumns = {
            @JoinColumn(
                name = "tag_id", 
                referencedColumnName = "id"
            )
        },
        inverseJoinColumns = {
            @JoinColumn(
                name = "post_id", 
                referencedColumnName = "id"
            )
        }
    )
private List<Post> posts;

但你的问题...... 你试图保存一个分离的对象((意味着该对象的实例已保存到数据库但该对象不在会话中))使用持久化方法保存到数据库:

 Post post = new Post();
 post.setId(j);
 .
 .
 .
 em.persist(post)

persist方法用于向持久化上下文添加新实体(没有id设置)实例,即将实例从瞬态转换为持久状态。

当我们想要将记录插入数据库时​​,我们通常会调用它(持久化实体实例) 所以 如果你的对象有瞬态或持久状态,你可以使用persist方法,但如果你的对象被分离,你应该使用merge方法来保存它

答案 1 :(得分:0)

而不是:

  

@ManyToMany(cascade = CascadeType.ALL)   @JoinTable私人名单&lt;发布&gt;讯息;

尝试以下方法:

private List<Post> posts = new ArrayList<>();

@ManyToMany(cascade = CascadeType.ALL)
@JoinTable(
    name = "posts_tags",
            joinColumns = { @JoinColumn(name = "fk_tags") },
            inverseJoinColumns = { @JoinColumn(name = "fk_posts") }
)
public List<Post> getPosts() {
    return posts;
}

public void setPosts(List<Post> posts) {
    this.posts = posts;
}

这里hibernate将创建一个名为(posts_tags)的中间表,用于多对多关系映射。

现在让我们简化DAO服务:

@PersistenceContext(unitName = "myPersistenceUnit")
private EntityManager em;

@Transactional(value = "myTransactionManager",propagation = Propagation.REQUIRED)
public Post add(Post post) {
    em.persist(post);
    return post;
}