英文:
Spring + Hibernate :Unable to delete child in unidirectional relationship
问题
我在这里尝试找到类似的问题,我找到了这个链接,但它并没有帮助太多。
这个链接是我所遇到的确切问题。问题是@OnDelete是否强制我建立双向关系?如果可能的话,我想保持单向关系。
我想要做的是从帖子(父级)中删除评论(子级);
每次我尝试这样做,我都会收到以下错误:
java.sql.SQLIntegrityConstraintViolationException: 无法删除或更新父行:外键约束失败(`blogapp2`.`post_comments`,CONSTRAINT `FKrvgf8o4dg5kamt01me5gjqodf` FOREIGN KEY (`comments_id`) REFERENCES `comment` (`id`))
这是我的代码
删除方法
@GetMapping("/dashboard/showposts/deletecomment/{id}")
public String deleteComment(@PathVariable("id") Long id) {
commentService.deleteComment(id);
return "redirect:/admin/dashboard/showposts";
}
在Post类中
@OneToMany(cascade = CascadeType.ALL)
private List<Comment> comments = new ArrayList<>();
在Comment类中没有对父级的引用。我如何从数据库中删除评论?我提到级联在没有问题的情况下工作,所以当我删除父级时,所有子级也会被删除。
任何帮助将不胜感激!
附注:我修改了处理方法,使其如下所示
@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";
}
英文:
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";
}
答案1
得分: 2
你可以在不创建双向关系的情况下完成这个操作,但这样做有一个需要注意的地方,稍后我会谈到,让我们看看如何在单向关系中实现。
首先,你需要在实体关系上指定orphanRemoval=true
。
@OneToMany(cascade = { CascadeType.ALL }, orphanRemoval = true)
List<Comment> comments = new ArrayList();
假设你的评论类中已经实现了equals
和hashCode
方法,
然后你只需要根据评论的id加载评论实体,然后调用:
Comment comment = dao.findById(id);
comments.remove(comment);
这将从表中删除评论,而其他评论将保持不变。
另一种方法是遍历评论列表,查找匹配的评论对象(将该方法添加到事务中)。
@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;
}
}
注意:
1. post.getComments() // 会从数据库加载所有评论
2. comments.remove(comment) // 会触发额外的INSERT语句
为什么会触发额外的INSERT语句?
当你使用单向映射时,JPA提供程序(如Hibernate)会创建额外的连接表,实际上会在后台创建@ManyToMany
关系。
因此,它首先会从连接表中删除所有与关联的post_id
相关的条目,然后再将所有记录重新插入连接表,只是留下了我们删除的记录。
然后它会从评论表中删除该条目,所以在使用单向关系时,你需要承担性能损耗。
英文:
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.
答案2
得分: 0
根据错误消息,我假设除了 post
和 comments
表之外,您还有一个名为 post_comments
的连接表。
如果是这种情况,Hibernate 不知道它。您应该在 Post
类的 comments
字段中不仅使用 @OneToMany
,还应该使用 @JoinTable
注解。
英文:
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.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论