I´m creating my first Spring Boot application with the Java Persistence API to write to and read from a postgres database. I´ve looked through many tutorials and posts to figure out my exact problem and it seems like I currently have a bidirectional one-to-many relationship with two entities (Parent
and Child
), but the foreign-key of the child
column is always null
when I write to the database.
ParentEntity:
@Entity
@Entity
@Data
@NoArgsConstructor
@AllArgsConstructor
@Table(name = "tb_parent")
public class Parent {
@Schema(description = "id of the parent")
@Id @GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Schema(description = "child-list of the application")
@OneToMany(mappedBy = "parent", cascade = CascadeType.ALL, fetch=FetchType.LAZY, orphanRemoval = true)
private Set<Child> children;
}
ChildEntity:
@Entity
@Data
@NoArgsConstructor
@AllArgsConstructor
@Table(name = "tb_child")
public class Child{
@Schema(description = "id of the child")
@Id @GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@JsonBackReference
@ManyToOne(targetEntity = Parent.class, fetch = FetchType.LAZY)
@JoinColumn(name = "parent_id", referencedColumnName = "id", updatable = true, insertable = true)
private Parent parent;
}
ParentService:
...
@Override
public Parent create(Parent parent) {
log.info("save new parent: {}", parent);
return parentRepo.save(parent); // the repo is an interface that extends the JpaRepository
}
...
After invoking the create
method, I have a parent
row in the tb_parent
with a generated id
and one or more child
rows in the tb_child
with a generated id
and a null
value for the parent_id
column.
Even though I´m able to find lots of posts describing a similar issue, I wasn´t yet able to find a solution that works for me.
Update #1:
A common suggestion is to manually set the parent
object in all child
elements. However, this results in a Stackoverflow Exception due to the circular structure.
public void setChildren(Set<Child> children) {
children.forEach(child -> child.setParent(this));
this.children = children;
}
Additionally, it kinda feels off because almost everything is managed automatically by the JPA Annotations and then you have to manually sync the data.
CodePudding user response:
Thanks to Georgy Lvov I was able to find the most effective solution. I had to do the following steps:
- remove the
@Data
annotation as suggested by Georgy Lvov (Thank you so much!) This basically avoids the generated getter and setter methods for all attributes and the methods equals(), hashCode(), and toString() by Lombok which caused the Stackoverflow Exception. - annotate the
Set<Child> children;
variable in theParent
class with the@JsonManagedReference
annotation. see below:
@JsonManagedReference
@Schema(description = "child-list of the application")
@OneToMany(mappedBy = "parent", cascade = CascadeType.ALL, fetch=FetchType.LAZY, orphanRemoval = true)
private Set<Child> children;
- annotate the
private Parent parent;
in theChild
class with the@JsonBackReference
annotation. see below:
@JsonBackReference
@ManyToOne(targetEntity = Parent.class, fetch = FetchType.LAZY)
@JoinColumn(name = "parent_id", referencedColumnName = "id", updatable = true, insertable = true)
private Parent parent;
The @JsonBackReference
also seems to avoid the circular structure when you create an openapi.json
file.