Reputation: 459
i tried finding similar issue here and i found this here but it did not help much.
this here is the exact issue i have. Thing is the @OnDelete forces me to make a bidirectional relationship right? I would like to keep it unidirectional if possible.
What i want to do is delete a comment (child) from a post (parent);
every time i am trying to do that i receive this error
java.sql.SQLIntegrityConstraintViolationException: Cannot delete or update a parent row: a foreign key constraint fails (`blogapp2`.`post_comments`, CONSTRAINT `FKrvgf8o4dg5kamt01me5gjqodf` FOREIGN KEY (`comments_id`) REFERENCES `comment` (`id`))
this is my code the delete method
@GetMapping("/dashboard/showposts/deletecomment/{id}")
public String deleteComment(@PathVariable("id") Long id) {
commentService.deleteComment(id);
return "redirect:/admin/dashboard/showposts";
}
in Post
@OneToMany(cascade = CascadeType.ALL)
private List<Comment> comments = new ArrayList<>();
in Comment there is no reference to the Parent. How can i delete the Comment from the database? i mention that cascade works with no issues so when i delete the parent all the children are deleted aswell. Any help would be greatly appreciated !
L.E:I modified my handler method to look like this
@GetMapping("/dashboard/showposts/deletecomment/{id}")
public String deleteComment(@PathVariable("id") Long id) {
List<Comment> comments = commentService.findAll();
Comment comment = commentService.findBYId(id);
comments.remove(comment);
return "redirect:/admin/dashboard/showposts";
}
Upvotes: 1
Views: 2149
Reputation: 1148
You can do it without creating bidirectional relationship but there is one caveat in doing so and I would come to that later, let's see how you can do that in unidirectional relationship.
First you need to specify the orphanRemoval=true
on your entity relation
@OneToMany(cascade = { CascadeType.ALL }, orphanRemoval = true)
List<Comment> comments = new ArrayList();
// Now I am assuming you have equals and hash code methods are implemented in your comment class,
// So all you need to load the Comment Entity by its id and then have to call
Comment comment = dao.findById(id);
comments.remove(comment);
// This will delete the comment from table and will keep all comments as it is.
// Another way is to iterate the comments list and find matching Comment object (add the method in transaction)
@Service
class PostService {
@Transactional
public Comment deleteComment(Integer commentId) {
Post post = repository.findById(id);
List<Comment> comments = post.getComments();
Comment comment = comments.stream().filter(c -> c.getId().equals(commentId)).findAny()
.orElseThrow(() -> new IllegalArgumentException("Invalid comment id"));
comments.remove(comment);
return comment;
}
}
Caveats:
1. post.getComments() // will load all comments from database
2. comments.remove(comment) // will trigger additional INSERT statements
Why additional insert statements will be triggered?
When you use uni-directional mapping, JPA provider (hibernate) will create additional junction table and your relation becomes @ManyToMany
at the background.
So it will first Delete all the entries from junction table passing associated post_id
and then insert all the records back to junction table, leaving the record we deleted.
Then it will delete the entry from comment table, so its a performance penalty you have to pay using unidirectional relation.
Upvotes: 2
Reputation: 807
By the error message, I assume that besides tables post
and comments
, you have a join table named post_comments
.
If thats the case, hibernate is not aware of it. You should use not only @OneToMany
but @JoinTable
annotation as well in the comments
field of Post
class.
Upvotes: 0