Given a bidirectional one-to-many relation like the following:
{code:java}@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<>();
//Getters and setters are omitted for brevity }
@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;
//Getters and setters are omitted for brevity }{code}
The next code throws an exception caused by calling post.getComments().isEmpty() with a merge operation:
{code:java}Post post = entityManager.find(Post.class, 1L); post.addComment(new PostComment(“This post rocks!”)); post.getComments().isEmpty(); // this causes an exception fails entityManager.merge(post);{code}
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 ) |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". |
|