Hibernate cascade delete orphan

user1480528 picture user1480528 · Aug 21, 2012 · Viewed 8.6k times · Source

I have 2 entities: News and NewsComment

@Entity
@Table(name = "news", schema = "city")
public class News {

        private Set<CommentNews> comments = new HashSet<CommentNews>();
        ...
    @OneToMany(cascade={javax.persistence.CascadeType.ALL})
    @Cascade(CascadeType.DELETE_ORPHAN)
    @JoinColumn(name="news_id")
    public Set<CommentNews> getComments() {
        return comments;
    }
}

and

@Entity
@Table(name = "comment_news", schema = "city")
public class CommentNews {
private News news;            
    ...

    @ManyToOne
@Cascade(CascadeType.DELETE_ORPHAN)
@JoinColumn(name = "news_id")
public News getNews() {
    return news;
}
}

and code like this one:

public void delete(int id) {
        T obj = null;
        session = HibernateUtil.openSession();
        try {
            session.beginTransaction();
            obj = (T) session.get(persistentClass, id);
            session.delete(obj);
            session.getTransaction().commit();
        } catch (HibernateException e) {
            session.getTransaction().rollback();
        } finally {
            session.close();
        }
    }

I get

Hibernate: update city.comment_news set news_id=null where news_id=?
    WARN : org.hibernate.util.JDBCExceptionReporter - SQL Error: 1048, SQLState: 23000
    ERROR: org.hibernate.util.JDBCExceptionReporter - Column 'news_id' cannot be null
    ERROR: org.hibernate.event.def.AbstractFlushingEventListener - Could not synchronize database state with session
    org.hibernate.exception.ConstraintViolationException: Could not execute JDBC batch update Caused by: com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolationException: 
Column 'news_id' cannot be null

I want cascade delete News and CommentNews together

Answer

Alex Barnes picture Alex Barnes · Aug 21, 2012

The mapping here is incorrect:

On the owned side you should use mappedBy to show that the mapping (JoinColumn) is on the other side. You shouldn't have JoinColumn on both sides.

You should use the JPA annotations which include the orphanRemoval property as part of the OneToMany.

@Entity
@Table(name = "news", schema = "city")
public class News {
    @OneToMany(mappedBy = "news", cascade={javax.persistence.CascadeType.ALL}, orphanRemoval = true)
    public Set<CommentNews> getComments() {
        return comments;
    }
}

and on the owning side you shouldn't declare the cascade behaviour. This was done on the owned side.

@Entity
@Table(name = "comment_news", schema = "city")
public class CommentNews {
    @ManyToOne
    @JoinColumn(name = "news_id")
    public News getNews() {
        return news;
    }
}

Hope that works for you.