Issue
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
Solution
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 usinggetPlayers.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
}
Answered By - Martin Frey