Given a bidirectional one-to-many relation like the following:
@Entity
public class Post {
@Id
private Long id;
private String title;
@OneToMany(mappedBy = "post", cascade = CascadeType.ALL, orphanRemoval = true)
private List<PostComment> comments = new ArrayList<>();
}
@Entity
public static class PostComment {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String review;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "post_id")
private Post post;
}
The next code throws an exception caused by calling post.getComments().isEmpty() with a merge operation:
Post post = entityManager.find(Post.class, 1L);
post.addComment(new PostComment(“This post rocks!”));
post.getComments().isEmpty(); entityManager.merge(post);
A couple of things to mention:
- Although calling isEmpty() is useless here, it serves as a testing propose. Deleting this call avoids the exception.
- Retrieving the post along with its comments using a "LEFT JOIN FETCH" query not only avoids the exception but also is better in terms of performance.
- Calling entityManager.persist(post) instead of entityManager.merge(post) also avoids the exception. In fact, both calls are redundant since the post is being managed by the current running Persistence Context.
According to @vladmihalcea (see https://github.com/vladmihalcea/high-performance-java-persistence/pull/51): "It looks like the merge generates an extra copy of the transient entity which has an id of null as if it was loaded from the DB". |