Home > Blockchain >  Foreign-key in tb_child is null with bidirectional one-to-many relationship
Foreign-key in tb_child is null with bidirectional one-to-many relationship

Time:02-10

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:

  1. 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.
  2. annotate the Set<Child> children; variable in the Parent 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;
  1. annotate the private Parent parent; in the Child 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.

  • Related