I am having an issue while trying to conduct a deletion in a many-to-many relationship. First of all I'd like to mention the story. I have two entity classes called Post and Category, Here Posts are associated with Categories, and it is also true other way around. I can create categories and post, and when creating or editing a post I can associate categories no problem. The issue arises when I remove a category from a post. There is no exception or error thrown, but it does not remove it.
Normally as you will see below the code, in a post set, when I remove a category object and save the object, hibernate will take care of removing the regarding relation in the shared table, but it does not just happen!
Other than that, I've tried multiple solutions, but they did not quite work out either.
- http://ift.tt/1RfYeT3
- Hibernate Bidirectional ManyToMany delete issue 3.http://ift.tt/1RfYeT7 4.Hibernate Bi-Directional Many to Many association creates duplicates 5.http://ift.tt/1RfYeTb
Post Entity
@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;
}
}
Category Entity
@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
@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());
}
Edit Post Edit DAO Method
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
For a couple of days, I've been googling and checking out different sources and finally I've decided to test entire structure and the entity classes in Non J2EE environments using Hibernate and EclipseLink JPA without Spring. I've come to realize that while using the application in the Spring container, the issue still continues, but without Spring environment, surprisingly there is no such issue at all. All tests work fine, so does bi directional many to many annotation I've been dwelling on getting it work.
I'd like to hereby share the spring configuration and maven pom configuration for your observation and suggestions what to do. Briefly I manage the transactions on hibernate's side. If you see any gap or wrong I'll really appreciate your help!
Thanks again
applicationContext.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://ift.tt/GArMu6"
xmlns:xsi="http://ift.tt/ra1lAU" xmlns:p="http://ift.tt/1jdM0fE"
xmlns:tx="http://ift.tt/OGfeU2" xmlns:context="http://ift.tt/GArMu7"
xsi:schemaLocation="http://ift.tt/GArMu6
http://ift.tt/1jdM0fG
http://ift.tt/GArMu7
http://ift.tt/1jdLYo7
http://ift.tt/OGfeU2
http://ift.tt/18tm2Tg">
<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://ift.tt/HBk9RF"> 4.0.0 com.tugrulaslan WebApp war 1.0-SNAPSHOT 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>
Aucun commentaire:
Enregistrer un commentaire