1

I am working on a project and I have felt like in @OneToMany Unidirectional association with @JoinColumn in JPA with springboot generates extra queries. For example if we have 2 entities

@Entity(name = "Post")
@Table(name = "post")
public class Post {
 
    @Id
    @GeneratedValue
    private Long id;
 
    private String title;
 
    @OneToMany(
        cascade = CascadeType.ALL,
        orphanRemoval = true
    )
    @JoinColumn(name = "post_id")
    private List<PostComment> comments = new ArrayList<>();
 
    //Constructors, getters and setters removed for brevity
}
 
@Entity(name = "PostComment")
@Table(name = "post_comment")
public class PostComment {
 
    @Id
    @GeneratedValue
    private Long id;
 
    private String review;
 
    //Constructors, getters and setters removed for brevity
}

when we run the following code

Post post = new Post("First post");
 
post.addComment(
    new PostComment("My first review")
);
post.addComment(
    new PostComment("My second review")
);
post.addComment(
    new PostComment("My third review")
);
 
entityManager.persist(post);

it generates following queries

insert into post (title, id)
values ('First post', 1)
 
insert into post_comment (review, id)
values ('My first review', 2)
 
insert into post_comment (review, id)
values ('My second review', 3)
 
insert into post_comment (review, id)
values ('My third review', 4)
 
update post_comment set post_id = 1 where id = 2
 
update post_comment set post_id = 1 where id =  3
 
update post_comment set post_id = 1 where id =  4

Now my question is that why does JPA updates post_comment records after inserting post_comment records ? why didn't JPA insert the post_comment records with the post_id while it was inserting records in post_comment table so that it don't have to update records again ?

Umair
  • 585
  • 3
  • 9
  • 21
  • Duplicate? https://stackoverflow.com/questions/25379046/why-hibernate-generates-insert-and-update-for-onetomany-mapping – a_a Dec 31 '22 at 22:06
  • 1
    You are using unidirectional association, PostComment doesn't know to which Post it belongs, for that reason you have that generated update statements. If you use a biderectional association, you will avoid those additional update statements, the best practice is to use bidirectional association for OneToMany. – xmen-5 Dec 31 '22 at 23:20
  • Does this answer your question? [Why hibernate generates insert and update for OneToMany mapping](https://stackoverflow.com/questions/25379046/why-hibernate-generates-insert-and-update-for-onetomany-mapping) – K.Nicholas Jan 01 '23 at 07:08
  • @xmen-5 the JPA first persists the post, so it has the post_id before persisting the post-comment, So then how does not it now that this post_comment belongs to which post ? – Umair Jan 01 '23 at 21:59
  • @K.Nicholas this answers gives the solution but doesn't explain that why JPA has this behaviour. I don't want solution, i want to understand the problem that why does JPA behaves like this – Umair Jan 01 '23 at 22:01
  • @a_a this answers gives the solution but doesn't explain that why JPA has this behaviour. I don't want solution, i want to understand the problem that why does JPA behaves like this – Umair Jan 01 '23 at 22:01
  • This user has never accepted an answer. – K.Nicholas Jan 09 '23 at 01:41

1 Answers1

0

You are depending on the CascadeType.ALL to insert the PostComments for you. Why is that? I consider that a JPA anti-pattern. JPA specifies that the owner of the relationship will persist relations. See If the relationship is bidirectional, the mappedBy element must be used to specify the relationship field or property of the entity that is the owner of the relationship. You have not specified an owner of the relationship.

What in the JPA specification can you point to that dictates that using the CascadeType should be implemented in any specific fashion?

What you show kind of makes sense to me. The Post is saved, the PostComments are saved b/c of the CascadeType, and then the Post id updated into the PostComments. You didn't set the Post id into the PostComments yourself so you don't have any say about how the implementation does it. I have seen CascaseType do some interesting things, but it's still an anti-pattern as far as I'm concerned. If you don't understand it, don't use it!

Besides that, you have also added a static = new ArrayList<>() on comments. Another anti-pattern. The majority of those new ArrayLists will be tossed onto the garbage heap in very short order. Even though Java manages memory for you, you should have some idea of how you are using it.

Short answer, the PostComments should be saved by you specifically, but only when you already have saved the Post and it is ready to be set into the PostComment. Of course, you should have the Post and the ManyToOne in the PostComment so you can do that.

I don't know if you've investigated the Query behaviors of the related Entities, but I think you'll find more surprises there as well. Since I have already done that, I make these comments.

References:

What is the "owning side" in an ORM mapping?

37.1 Entities

K.Nicholas
  • 10,956
  • 4
  • 46
  • 66