Suppose there are 2 entities, which represent a blog Post and its comments. One blog can have multiple comments:
@Entity
public class Post {
@Id
@GeneratedValue
private Long id;
private String name;
@OneToMany(cascade = CascadeType.ALL, orphanRemoval = true, mappedBy = "post")
private List<Comment> comments;
}
@Entity
@IdClass(CommentPK.class)
public class Comment {
@Id
private Long id;
@Id
@ManyToOne
private Post post;
private String content;
}
class CommentPK implements Serializable {
private Long post;
private Long id;
}
I want Comment to have composite PK of (post_id, comment_id), where comment_id is a sequence within one post, for example:
| post_id | comment_id | content |
| 1 | 1 | 123 |
| 1 | 2 | 456 |
| 1 | 3 | Hello SO |
| 2 | 1 | New Post | << Post #2 has comment IDs starting from 1 again
While mapping works, I can not save post, because comment does not have ID. This is why I've added entity listeners:
@PrePersist
@PreUpdate
public void preProcess(Post post) {
int id = 1;
for (Comment comment : post.getComments()) {
comment.setPost(post);
comment.setId(id++);
}
}
It works on the first post persist, however if I add new comments to persisted post, entity listener is not called. I have also tried adding entity listener for Comment with the similar logic, but it is just not not invoked
@Test
public void testPersistAndUpdate() {
Post post = new Post();
post.setName("Test");
Comment comment1 = new Comment();
comment1.setPost(post);
comment1.setContent("Comment 1");
List<Comment> comments = new ArrayList<>();
comments.add(comment1);
post.setComments(comments);
Post savedPost = postRepository.saveAndFlush(post); // Spring Data JPA repository, all OK for now
// create new Comment
Comment comment2 = new Comment();
comment2.setPost(post);
comment2.setContent("Comment 2");
savedPost.getComments().add(comment2);
savedPost = postRepository.saveAndFlush(savedPost); // here entity listener is not invoked and exception is thrown
}
I am getting an exception:
javax.persistence.PersistenceException: org.hibernate.HibernateException: No part of a composite identifier may be null
Questions
What is the common practice of modeling relations like these? (still keeping composite key a requirement) As it feels pretty uncomfortable dealing with it through JPA/Hibernate now
If keeping the mapping from the example, is it possible to make
@PrePersistforCommentworking, whenPostattributes are not updated, but theCommentis new and should be persisted?