2015-06-19 73 views
0

我在尝试在多对多关系中进行删除时遇到问题。首先我想提一下这个故事。我有两个名为Post和Category的实体类,这里的Posts与Categories有关,其他方式也是如此。我可以创建类别并发布,创建或编辑帖子时,我可以将类别关联起来没有问题。当我从帖子中删除某个类别时,就会出现问题。没有抛出异常或错误,但不会将其删除。休眠春季双向多对多删除不起作用

正常情况下,您将在下面看到代码,在一个帖子集中,当我删除一个类别对象并保存该对象时,hibernate将负责删除共享表中的关系关系,但它不会发生!

除此之外,我尝试了多种解决方案,但他们也没有完全解决。

  1. https://forum.hibernate.org/viewtopic.php?f=1&t=17
  2. Hibernate Bidirectional ManyToMany delete issue 3. http://www.codereye.com/2009/06/hibernate-bi-directional-many-to-many.html 4. Hibernate Bi-Directional Many to Many association creates duplicates 5. https://howtoprogramwithjava.com/hibernate-manytomany-unidirectional-bidirectional/

发布实体

@Entity 
@Table(name = "posts") 
public class Post { 

    @Id 
    @Column(name = "postid") 
    @GeneratedValue(strategy = GenerationType.AUTO) 
    private long postId; 

    @Column(name = "postTitle") 
    private String postTitle; 

    @Column(name = "postContext") 
    @Type(type = "text") 
    private String postContext; 

    @Column(name = "postedDate") 
    private Date postedDate; 

    @Column(name = "visitCount") 
    private long visitCount; 

    @Column(name = "publishable") 
    private boolean publishable; 

    @ManyToMany(cascade = {CascadeType.PERSIST, CascadeType.MERGE}, targetEntity = Category.class, fetch = FetchType.EAGER) 
    //@ManyToMany(cascade = {CascadeType.PERSIST, CascadeType.MERGE}, fetch = FetchType.EAGER,mappedBy = "posts") 
    @JoinTable(name = "post_category", joinColumns = {@JoinColumn(name = "postid")}, inverseJoinColumns = {@JoinColumn(name = "categoryid")}) 
    private Set<Category> categories = new HashSet<>(); 

    @OneToOne(cascade = CascadeType.ALL) 
    private User user; 

    public Post() { 
    } 

    public Post(String postTitle, String postContext, Date postedDate, boolean publishable, Set<Category> categories, User user) { 
     this.postTitle = postTitle; 
     this.postContext = postContext; 
     this.postedDate = postedDate; 
     this.publishable = publishable; 
     this.categories = categories; 
     this.user = user; 
    } 

    public long getPostId() { 
     return postId; 
    } 

    public void setPostId(long postId) { 
     this.postId = postId; 
    } 

    public String getPostTitle() { 
     return postTitle; 
    } 

    public void setPostTitle(String postTitle) { 
     this.postTitle = postTitle; 
    } 

    public String getPostContext() { 
     return postContext; 
    } 

    public void setPostContext(String postContext) { 
     this.postContext = postContext; 
    } 

    public Date getPostedDate() { 
     return postedDate; 
    } 

    public long getVisitCount() { 
     return visitCount; 
    } 

    public void setVisitCount(long visitCount) { 
     this.visitCount = visitCount; 
    } 

    public void setPostedDate(Date postedDate) { 
     this.postedDate = postedDate; 
    } 

    public boolean isPublishable() { 
     return publishable; 
    } 

    public void setPublishable(boolean publishable) { 
     this.publishable = publishable; 
    } 

    public Set<Category> getCategories() { 
     return categories; 
    } 

    public void setCategories(Set<Category> categories) { 
     this.categories = categories; 
    } 

    public User getUser() { 
     return user; 
    } 

    public void setUser(User user) { 
     this.user = user; 
    } 
} 

类别实体

@Entity 
@Table(name = "categories") 
public class Category { 

    @Id 
    @Column(name = "categoryid") 
    @GeneratedValue(strategy = GenerationType.AUTO) 
    private long categoryId; 

    @Column(name = "categoryName") 
    private String categoryName; 

    @Column(name = "createdDate") 
    private Date createdDate; 

    @ManyToOne 
    @JoinColumn(name = "parent_category_id") 
    private Category parentCategory; 

    @OneToMany(mappedBy = "parentCategory", cascade = CascadeType.ALL, fetch = FetchType.EAGER) 
    public Set<Category> subCategories = new HashSet<>(); 

    // @ManyToMany(cascade = {CascadeType.PERSIST, CascadeType.MERGE}, fetch = FetchType.EAGER, targetEntity = Post.class) 
    // @JoinTable(name = "post_category", joinColumns = {@JoinColumn(name = "categoryid")}, inverseJoinColumns = {@JoinColumn(name = "postid")}) 
    @ManyToMany(cascade = {CascadeType.PERSIST, CascadeType.MERGE}, fetch = FetchType.EAGER,mappedBy = "categories") 
    private Set<Post> posts = new HashSet<>(); 

    public Category() { 
    } 

    public Category(String categoryName) { 
     this.categoryName = categoryName; 
    } 

    public Category(String categoryName, Date createdDate, Category parentCategory) { 
     this.categoryName = categoryName; 
     this.createdDate = createdDate; 
     this.parentCategory = parentCategory; 
     this.subCategories = new HashSet<>(); 
     if (parentCategory != null) { 
      parentCategory.subCategories.add(this); 
     } 
    } 

    public Set<Post> getPosts() { 
     return posts; 
    } 

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

    public long getCategoryId() { 
     return categoryId; 
    } 

    public void setCategoryId(long categoryId) { 
     this.categoryId = categoryId; 
    } 

    public String getCategoryName() { 
     return categoryName; 
    } 

    public void setCategoryName(String categoryName) { 
     this.categoryName = categoryName; 
    } 

    public Date getCreatedDate() { 
     return createdDate; 
    } 

    public void setCreatedDate(Date createdDate) { 
     this.createdDate = createdDate; 
    } 

    public Category getParentCategory() { 
     return parentCategory; 
    } 

    public void setParentCategory(Category parentCategory) { 
     this.parentCategory = parentCategory; 
    } 

    public Set<Category> getSubCategories() { 
     return subCategories; 
    } 

    public void setSubCategories(Set<Category> subCategories) { 
     this.subCategories = subCategories; 
    } 
} 

测试

@Test 
    public void stage09_EditCreatedPostTest() { 
     //Fetch the post 
     Post post = appService.getPostByName(postName); 

     //Fetch the child category; 
     Category category = appService.getCategoryByName(childCatName); 

     //Remove the child category 
     post.getCategories().remove(category); 

     //Selected child category is not null 
     assertNotNull(category); 

     appService.editPost(post); 

     //Fetch the post again 
     Post post2 = appService.getPostByName(postName); 

     //Check the post2 object it is not null 
     assertNotNull(post2); 

     //Check category size 
     assertEquals(1, post2.getCategories().size()); 
    } 

编辑 帖子编辑DAO方法

public void editPost(Post post) { 
     Session session = sessionFactory.openSession(); 
     Transaction transaction = session.beginTransaction(); 
     try { 
      session.update(post); 
      transaction.commit(); 
     } catch (HibernateException e) { 
      System.err.println(e); 
      transaction.rollback(); 
     } finally { 
      session.close(); 
     } 
    } 

UPDATE

有一段时间,我一直在使用Google和检查不同的来源,最后我决定在非J2EE环境中使用Hibernate和EclipseLink JPA测试整个结构和实体类,而不使用Spring。我已经认识到,在Spring容器中使用应用程序时,问题仍然存在,但没有Spring环境,令人惊讶的是根本没有这样的问题。所有的测试都可以正常工作,所以双向的多方面的注释我一直在努力让它工作。

我想特此分享spring配置和maven pom配置,以便为您的观察和建议做些什么。简而言之,我在Hibernate的一端管理事务。如果您发现任何缺陷或错误,我将非常感谢您的帮助!

再次感谢

的applicationContext.xml

<?xml version="1.0" encoding="UTF-8"?> 
<beans xmlns="http://www.springframework.org/schema/beans" 
     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p" 
     xmlns:tx="http://www.springframework.org/schema/tx" xmlns:context="http://www.springframework.org/schema/context" 
     xsi:schemaLocation="http://www.springframework.org/schema/beans 
    http://www.springframework.org/schema/beans/spring-beans.xsd 
    http://www.springframework.org/schema/context 
    http://www.springframework.org/schema/context/spring-context.xsd 
    http://www.springframework.org/schema/tx 
    http://www.springframework.org/schema/tx/spring-tx.xsd"> 

    <context:property-placeholder location="classpath:hibernate.properties"/> 

    <!-- Hibernate connection configuration --> 
    <bean id="dataSource" 
      class="org.springframework.jdbc.datasource.DriverManagerDataSource"> 
     <property name="driverClassName" value="${orm.connection.driver_class}"/> 
     <property name="url" value="${orm.connection.url}"/> 
     <property name="username" value="${orm.connection.username}"/> 
     <property name="password" value="${orm.connection.password}"/> 
    </bean> 

    <!-- Hibernate configuration settings --> 
    <bean id="sessionFactory" 
      class="org.springframework.orm.hibernate4.LocalSessionFactoryBean"> 
     <property name="dataSource" ref="dataSource"/> 
     <property name="packagesToScan" value="com.tugrulaslan.entity"/> 
     <property name="hibernateProperties"> 
      <props> 
       <prop key="hibernate.dialect">${orm.dialect}</prop> 
       <prop key="hibernate.show_sql">${orm.show_sql}</prop> 
       <prop key="hibernate.hbm2ddl.auto">${orm.hbm2ddl.auto}</prop> 
       <!-- --> <prop key="current_session_context_class">thread</prop> 
      </props> 
     </property> 
    </bean> 

    <!-- Hibernate Session Factory creation 
    <bean id="transactionManager" 
      class="org.springframework.orm.hibernate4.HibernateTransactionManager"> 
     <property name="sessionFactory" ref="sessionFactory"/> 
    </bean> 

    <tx:annotation-driven transaction-manager="transactionManager"/> --> 

    <context:component-scan base-package="com.tugrulaslan"/> 
</beans> 

的pom.xml http://maven.apache.org/maven-v4_0_0.xsd“> 4.0.0 COM。tugrulaslan Web应用程序 战争 1.0快照 BlogWebApp的Maven的webapp http://maven.apache.org

<properties> 
    <project-java.version>1.7</project-java.version> 
    <maven-compiler-plugin.version>3.1</maven-compiler-plugin.version> 
    <junit.version>4.11</junit.version> 
    <mysql-connector.version>5.1.34</mysql-connector.version> 
    <hibernate.version>4.3.6.Final</hibernate.version> 
    <javax-persistance-api.version>1.0.2</javax-persistance-api.version> 
    <spring.version>4.0.6.RELEASE</spring.version> 
</properties> 

<dependencies> 
    <dependency> 
     <groupId>junit</groupId> 
     <artifactId>junit</artifactId> 
     <version>${junit.version}</version> 
     <scope>test</scope> 
    </dependency> 
    <dependency> 
     <groupId>mysql</groupId> 
     <artifactId>mysql-connector-java</artifactId> 
     <version>${mysql-connector.version}</version> 
    </dependency> 
    <dependency> 
     <groupId>org.hibernate</groupId> 
     <artifactId>hibernate-core</artifactId> 
     <version>${hibernate.version}</version> 
    </dependency> 
    <dependency> 
     <groupId>javax.persistence</groupId> 
     <artifactId>persistence-api</artifactId> 
     <version>${javax-persistance-api.version}</version> 
    </dependency> 
    <dependency> 
     <groupId>org.springframework</groupId> 
     <artifactId>spring-context</artifactId> 
     <version>${spring.version}</version> 
    </dependency> 
    <dependency> 
     <groupId>org.springframework</groupId> 
     <artifactId>spring-orm</artifactId> 
     <version>${spring.version}</version> 
    </dependency> 
    <!-- 
    <dependency> 
     <groupId>org.springframework</groupId> 
     <artifactId>spring-tx</artifactId> 
     <version>${spring.version}</version> 
    </dependency>--> 
    <dependency> 
     <groupId>org.springframework</groupId> 
     <artifactId>spring-test</artifactId> 
     <version>${spring.version}</version> 
    </dependency> 
</dependencies> 
<build> 
    <finalName>BlogWebApp</finalName> 
    <plugins> 
     <plugin> 
      <groupId>org.apache.maven.plugins</groupId> 
      <artifactId>maven-compiler-plugin</artifactId> 
      <version>${maven-compiler-plugin.version}</version> 
      <configuration> 
       <source>${project-java.version}</source> 
       <target>${project-java.version}</target> 
      </configuration> 
     </plugin> 
    </plugins> 
</build> 

+0

你会得到什么错误?你有没有为ManyToMany关系尝试cascade = CascadeType.ALL? – Jay

+0

错误是由JUnit引发的,因为给定的情况不满足。在我编辑上面并检查帖子的类别大小应该是1,但它仍然是2.我已经尝试了大量的解决方案和组合,这些解决方案和组合在上面的列表方法中已被注释掉 –

回答

0

经过长期的研究后,提交并进行测试,我发现在调试应用程序时出现了什么问题。当我调试移除部分时,我突然注意到Set集合中的大小和元素与移除操作之前的相同。目标集合中的对象的等同性无法确定,因此无法继续执行删除操作。

在我已经认识到这一点之后,我立即覆盖了对象的equals方法,并且包含了唯一不可改变的字段,它只在我的情况下似乎是类别id,其他字段是直接的,互换。所以下面你会找到完整的Category实体和IntelliJ IDE生成的重写对象equals方法。

除此之外,我已经进行了两种情况的案例,以确定我恰好在类实体中定义的上述post集合中定义的级联选项是否至关重要,提及“cascade = {CascadeType.PERSIST,CascadeType .MERGE}“。因此,最终我意识到,在多对多关系中定义的相应级联的缺失或存在没有区别。它的存在并没有改变其他不同测试案例中经历的任何事情。

我希望我的问题和解决方案能够为阴影区域带来一些光线,并在出现类似问题时为您提供帮助。

@Entity 
@Table(name = "categories") 
public class Category { 

    @Id 
    @Column(name = "categoryid") 
    @GeneratedValue(strategy = GenerationType.AUTO) 
    private long categoryId; 

    @Column(name = "categoryName") 
    private String categoryName; 

    @Column(name = "createdDate") 
    private Date createdDate; 

    @ManyToOne 
    @JoinColumn(name = "parent_category_id") 
    private Category parentCategory; 

    @OneToMany(mappedBy = "parentCategory", cascade = CascadeType.ALL, fetch = FetchType.EAGER) 
    private Set<Category> subCategories = new HashSet<>(); 

    @ManyToMany(fetch = FetchType.EAGER, mappedBy = "categories") 
    private Set<Post> posts = new HashSet<>(); 

    public Category() { 
    } 

    public Category(String categoryName) { 
     this.categoryName = categoryName; 
    } 

    public Category(String categoryName, Date createdDate, Category parentCategory, Set<Category> subCategories, Set<Post> posts) { 
     this.categoryName = categoryName; 
     this.createdDate = createdDate; 
     this.parentCategory = parentCategory; 
     this.subCategories = new HashSet<>(); 
     if (parentCategory != null) { 
      parentCategory.subCategories.add(this); 
     } 
     this.subCategories = subCategories; 
     this.posts = posts; 
    } 

    public Set<Post> getPosts() { 
     return posts; 
    } 

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

    public long getCategoryId() { 
     return categoryId; 
    } 

    public void setCategoryId(long categoryId) { 
     this.categoryId = categoryId; 
    } 

    public String getCategoryName() { 
     return categoryName; 
    } 

    public void setCategoryName(String categoryName) { 
     this.categoryName = categoryName; 
    } 

    public Date getCreatedDate() { 
     return createdDate; 
    } 

    public void setCreatedDate(Date createdDate) { 
     this.createdDate = createdDate; 
    } 

    public Category getParentCategory() { 
     return parentCategory; 
    } 

    public void setParentCategory(Category parentCategory) { 
     this.parentCategory = parentCategory; 
    } 

    public Set<Category> getSubCategories() { 
     return subCategories; 
    } 

    public void setSubCategories(Set<Category> subCategories) { 
     this.subCategories = subCategories; 
    } 

    @Override 
    public boolean equals(Object o) { 
     if (this == o) return true; 
     if (o == null || getClass() != o.getClass()) return false; 

     Category category = (Category) o; 

     return categoryId == category.categoryId; 

    } 

    @Override 
    public int hashCode() { 
     return (int) (categoryId^(categoryId >>> 32)); 
    } 
0

在服务检查,如果你是后删除类似下面

session.getTransaction().commit(); 
+0

我已经包含了我的方法以供您观察 –