prd
prd

Reputation: 2321

Persist nested entities (one-to-many) with a bidirectional relationship

I am creating a Spring Boot web application that is supposed to receive a JSON document via HTTP, parse it to the respective entity class, and persist the object. The JSON is a representation of a Recipe instance, and one recipe can have multiple Step objects associated with it.

Recipe.java

@Entity
public class Recipe {

    @Id
    @GeneratedValue
    private Long id;

    @NotNull
    private String name;

    @OneToMany(mappedBy = "recipe", cascade = CascadeType.ALL)
    private Set<Step> steps;

    // Additional attributes, constructors, getters and setters omitted
}

Step.java

@Entity
public class Step {

    @Id
    @GeneratedValue
    private Long id;

    @NotNull
    private String name;

    @ManyToOne
    @JoinColumn(name = "RECIPE_ID")
    private Recipe recipe;

    // Additional attributes, constructors, getters and setters omitted
}

When sending the following JSON document to the application, however, the foreign key referencing RECIPE_ID within the step object is null, thus there is no connection between the recipe and its steps.

{
    "name": "Test recipe",
    "description": "Test description",
    "type": "Test",
    "cookingTime": 45,
    "preparationTime": 30,
    "thumbnail": "",
    "steps": [
        {
            "number": 1,
            "name": "First step",
            "content": "Test content",
            "image": ""
        },
        {
            "number": 2,
            "name": "Second step",
            "content": "Test content",
            "image": ""
        }
    ]
}

Should not the nested step objects also get persisted since CascadeType.ALL has been specified? Also, I am using a RestController to handle the request and a JpaRepository class for persistence.

Upvotes: 1

Views: 1806

Answers (2)

Rajneesh Prakash
Rajneesh Prakash

Reputation: 196

You can add @JsonBackReference annotation on @ManyToOne Side and @JsonManagedReference annotation on @OneToMany side.

@Entity
public class Recipe {

    @Id
    @GeneratedValue
    private Long id;

    @NotNull
    private String name;

    @OneToMany(mappedBy = "recipe", cascade = CascadeType.ALL)
    @JsonManagedReference("recipe_steps")
    private Set<Step> steps;

    // Additional attributes, constructors, getters and setters omitted
}


@Entity
public class Step {

    @Id
    @GeneratedValue
    private Long id;

    @NotNull
    private String name;

    @ManyToOne
    @JoinColumn(name = "RECIPE_ID")
    @JsonBackReference("recipe_steps")
    private Recipe recipe;

    // Additional attributes, constructors, getters and setters omitted
}

Upvotes: 4

Adil Khalil
Adil Khalil

Reputation: 2131

In your controller, you will have to do something like this.

for (Step step : recipe.getSteps()) {
    step.setRecipe(recipe);
}

You are basically missing the back-reference in the Step object which is null when you post.

Upvotes: 3

Related Questions