Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Spring data rest one to many delete child objects

I have a one to many relationship between Team and Player, I am able to create a Team with the following JSON

{
    "id": 1,
    "name": "MyTeam5",
    "players": [
        {
            "name": "player5"
        },
        {
            "name":"player10"
        }
    ]
}

However, when I try to delete a child object by removing it from the list with the following JSON

{
        "id": 1,
        "name": "MyTeam5",
        "players": [
            {
                "id": 2
                "name": "player5"
            }
        ]
    }

I get an error saying

"A collection with cascade=\"all-delete-orphan\" was no longer referenced by the owning entity instance: org.a.c.domain.user.Team.players"

Here is my Team and Player entity code -

@Data
@Entity
public class Team {

    @Id
    @GeneratedValue
    private Integer id;

    private String name;

    @JsonManagedReference
    @OneToMany(mappedBy="team", cascade= CascadeType.ALL, orphanRemoval=true)
    List<Player> players = new ArrayList<Player>();

}

@Data
@Entity
public class Player {

    @Id
    @GeneratedValue
    private Integer id;

    private String name;

    @JsonBackReference
    @ManyToOne
    @JoinColumn(name = "team_id")
    private Team team;
}

What am I doing wrong? Jackson is able to map one to many relation perfectly when I create a new Team with bunch of players but when I update / delete the players from Team json, it fails with the same error. Is it possible that the collection is recreated which is why hibernate throws error, if so how should I fix it? Please help

like image 309
Vijay Muvva Avatar asked Apr 27 '15 16:04

Vijay Muvva


Video Answer


1 Answers

The problem you are facing comes from the replacement of the players list. Hibernate needs to track which elements are removed and does this with the help of a specific list implementation (PersistentList as far as I remember).

The issue comes most likely when you, or something, call setPlayers. Effectively replacing the list with a new instance.

To fix the issue you have two possibilities:

  • avoid the call to setPlayers by using getPlayers.remove / add
  • or modify setPlayers to avoid setting a new list, but instead clearing the loaded list and add all elements from the argument list.

A quick example:

public void setPlayers(List list) {
    if (this.players == null) {
        this.players = list;
    } else {
        this.players.clear();
        this.players.addAll(list);
        // you might need to take care of bidirectional references here
    
}
like image 72
Martin Frey Avatar answered Sep 22 '22 07:09

Martin Frey