1

I'm trying to understand how Spring JPA works in creating (POST http action) resources under relationships (@OneToMany). I have 2 simples classes, Product and Comment. One productis related to many comments.

Product class :

@Entity
@Table(name = "product")
public class Product {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "product_id")
    private int productId;

    @Column(name = "name")
    private String name;

    @Column(name = "description")
    private String description;

    @OneToMany(cascade = { CascadeType.PERSIST})
    @JoinColumn(name = "product_id")
    private List<Comment> comments;

... getters and setters are also implemented

}

Comment class :

@Entity
@Table(name = "comment")
public class Comment {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "comment_id")
    private int commentId;

    @Column(name = "content")
    private String content;

    @Column(name = "product_id")
    private int productId;

... getters and setters

}

I implemented this @OneToMany relationship as unidirectional, on purpose, just to understand how it works. I also made basic controller and repository classes for both resources. What I am trying to understand is, when I send a Post request (using postman) to "/products" with a new product and its new comments at the same time as below :

enter image description here

I dont understand why I'm getting an error 500 from hibernate that successfully created the new product but did not for the comment because the comment is missing the foreign key. Of course I the get issue here. But since my relationship is unidirectional from the product, it should mean the product is leading the relation. So spring should synchronize the persisting operation (I added CascadeType.PERSIST), based on the product. In my request body, the product's comments list is filled with two new comments. This is supposed to set the comments list of the product and tell to hibernate that this product has two new comments. So my question is, why doesnt hibernate create the product then get the new id of this product and then create the two new comments with a foreign key set to this new product id ? Thank you for all your help.

idash
  • 29
  • 6
  • can you share how are you saving the entities? – Mohammed Fataka Apr 08 '23 at 23:04
  • Hi, thank you for giving me a hand. I’m just using the saving method of the repository : ‘’productRepository.save(product);’’ where I get the product from the @RequestBody as a method argument in my rest controller – idash Apr 09 '23 at 00:32

1 Answers1

0

so basically i am assuming you want on call of productRepository.save(product) it automatically saves comments with it, if so you need to change cascade to @OneToMany(cascade = { CascadeType.ALL}) otherwise you need manually to call both repositories to save entities, i tested your code, and only thing that is missing is to change cascade type

Mohammed Fataka
  • 150
  • 1
  • 8
  • Hi, thank you again for your help. Yes exactly, I want also the comments to be saved automatically. I dont understand why I have to put « CascadeType.ALL ». Isnt « CascadeType.PERSIST » supposed to be enough to tell hibernate that « when I create a product, if that product contains new comments, create them too » especially when it is a @OneToMany unidirectional relationship ? – idash Apr 09 '23 at 08:50
  • depends, both are valid if you want to let hibernate to only save child entity when calling parent `.save()` then `CascadeType.PERSIST` is enough but if you want an update, remove, or merge together then I suggest using `CascadeType.ALL` because in your case it is unidirectional meaning parent is the most important, check example 158 in [hibernate docs](https://docs.jboss.org/hibernate/orm/5.4/userguide/html_single/Hibernate_User_Guide.html#associations-one-to-one) for more information about cascading in unidirectional – Mohammed Fataka Apr 09 '23 at 12:58
  • Like you said, I just want to save child entity, thats why I really focused on CascadeType.PERSIST, so my question is why isnt it working with CascadeType.PERSIST to save child from parent (since parent is leading the relationship...) ? – idash Apr 09 '23 at 23:18
  • it works fine for me both with `CascadeType.PERSIST` and `CascadeType.ALL` – Mohammed Fataka Apr 10 '23 at 19:15
  • did you use something else like transactions or anything else ? Also can you add "spring.jpa.show-sql = true" on your file applications.properties and please share with me what console prints about hibernate database operations – idash Apr 11 '23 at 06:49
  • 1
    sure, `Hibernate: insert into product (description, name) values (?, ?) Hibernate: insert into comment (content, product_id) values (?, ?) Hibernate: update comment set product_id=? where comment_id=?` this is the log, full code is here (https://github.com/hammafataka/st_ov_answer) – Mohammed Fataka Apr 11 '23 at 08:44
  • thank you a lot for taking some time. I have another question though, how come in your logs, in the comment insert request, hibernate knows the value of "produit_id", because on my side, I get the error from here, throwing foreign key error and saying the produit_id is not valid – idash Apr 11 '23 at 10:09
  • maybe your db is wrongly created, i suggest to delete the table and let hibernate create it automatically as i have defined in `application.yaml` in github – Mohammed Fataka Apr 11 '23 at 11:05