Spring data rest一对多删除子对象
Spring data rest one to many delete child objects
我在 Team 和 Player 之间有一对多的关系,我可以用以下 JSON
创建一个 Team
{
"id": 1,
"name": "MyTeam5",
"players": [
{
"name": "player5"
},
{
"name":"player10"
}
]
}
但是,当我尝试通过使用以下 JSON
从列表中删除子对象来删除它时
{
"id": 1,
"name": "MyTeam5",
"players": [
{
"id": 2
"name": "player5"
}
]
}
我收到一条错误消息
"A collection with cascade=\"all-delete-orphan\" was no longer referenced by the owning entity instance: org.a.c.domain.user.Team.players"
这是我的团队和玩家实体代码 -
@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;
}
我做错了什么?当我用一群球员创建一个新团队时,杰克逊能够完美地映射一对多关系,但是当我更新/删除团队 json 中的球员时,它会失败并出现相同的错误。是否有可能重新创建集合,这就是休眠抛出错误的原因,如果是这样,我应该如何修复它?请帮助
您面临的问题来自players
列表的替换。 Hibernate 需要跟踪删除了哪些元素,并在特定列表实现的帮助下执行此操作(据我记得 PersistentList
)。
当您或其他人致电 setPlayers
时,问题最有可能出现。用新实例有效地替换列表。
要解决此问题,您有两种可能性:
- 使用
getPlayers.remove / add
避免调用 setPlayers
- 或修改
setPlayers
以避免设置新列表,而是清除加载的列表并添加参数列表中的所有元素。
一个简单的例子:
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
}
你可能是对的,集合正在被替换。
我假设有一个 TeamRepository
和一个 PlayerRepository
并且都被导出。这意味着 Team
响应会公开 players
link,您可以在其中 post 应该在团队中的玩家的 URI。如果播放器实体不存在,则首先创建它。这就是 Spring Data REST 的工作方式。
另请记住,公开数据库 ID 并不完全是 RESTful。资源的 ID 是它的 URI。
我在使用 spring-boot 时遇到过同样的问题。将 spring-boot-starter-parent 从 1.4.3.RELEASE 更新到 1.4.4.RELEASE 解决了问题:
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.4.4.RELEASE</version>
在后台,它正在更新一些依赖项,其中之一是 spring-data-rest-webmvc。它从 2.5.6.RELEASE 更新到 2.5.7.RELEASE:
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-rest-webmvc</artifactId>
<version>2.5.7.RELEASE</version>
这是解决我问题的特定依赖项更新。
不知道是bug还是spring-data-rest的特性。这个用例非常基础。但是由于使用所有这些框架(spring-data-rest、spring-data-jpa)或 spring-boot 默认堆栈都是关于抽象的,所以在我看来它是由 spring-data-rest 以某种方式处理的,因为只要发送的 JSON 是正确的并且 JPA 实体配置是正确的。理想情况下,我不想处理 Hibernate 的特殊性。
你在使用 PATCH 和 PUT 吗?
在 Spring 数据剩余的情况下,调用 PUT will replace your resource completely (and as I understand, create a new, untracked collection), whereas PATCH 只会部分更新您的实体。
在你的情况下,我会说使用 PATCH 是正确的调用,根据我的经验,有时可以解决这个问题。
我在 Team 和 Player 之间有一对多的关系,我可以用以下 JSON
创建一个 Team{
"id": 1,
"name": "MyTeam5",
"players": [
{
"name": "player5"
},
{
"name":"player10"
}
]
}
但是,当我尝试通过使用以下 JSON
从列表中删除子对象来删除它时{
"id": 1,
"name": "MyTeam5",
"players": [
{
"id": 2
"name": "player5"
}
]
}
我收到一条错误消息
"A collection with cascade=\"all-delete-orphan\" was no longer referenced by the owning entity instance: org.a.c.domain.user.Team.players"
这是我的团队和玩家实体代码 -
@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;
}
我做错了什么?当我用一群球员创建一个新团队时,杰克逊能够完美地映射一对多关系,但是当我更新/删除团队 json 中的球员时,它会失败并出现相同的错误。是否有可能重新创建集合,这就是休眠抛出错误的原因,如果是这样,我应该如何修复它?请帮助
您面临的问题来自players
列表的替换。 Hibernate 需要跟踪删除了哪些元素,并在特定列表实现的帮助下执行此操作(据我记得 PersistentList
)。
当您或其他人致电 setPlayers
时,问题最有可能出现。用新实例有效地替换列表。
要解决此问题,您有两种可能性:
- 使用
getPlayers.remove / add
避免调用 - 或修改
setPlayers
以避免设置新列表,而是清除加载的列表并添加参数列表中的所有元素。
setPlayers
一个简单的例子:
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
}
你可能是对的,集合正在被替换。
我假设有一个 TeamRepository
和一个 PlayerRepository
并且都被导出。这意味着 Team
响应会公开 players
link,您可以在其中 post 应该在团队中的玩家的 URI。如果播放器实体不存在,则首先创建它。这就是 Spring Data REST 的工作方式。
另请记住,公开数据库 ID 并不完全是 RESTful。资源的 ID 是它的 URI。
我在使用 spring-boot 时遇到过同样的问题。将 spring-boot-starter-parent 从 1.4.3.RELEASE 更新到 1.4.4.RELEASE 解决了问题:
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.4.4.RELEASE</version>
在后台,它正在更新一些依赖项,其中之一是 spring-data-rest-webmvc。它从 2.5.6.RELEASE 更新到 2.5.7.RELEASE:
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-rest-webmvc</artifactId>
<version>2.5.7.RELEASE</version>
这是解决我问题的特定依赖项更新。
不知道是bug还是spring-data-rest的特性。这个用例非常基础。但是由于使用所有这些框架(spring-data-rest、spring-data-jpa)或 spring-boot 默认堆栈都是关于抽象的,所以在我看来它是由 spring-data-rest 以某种方式处理的,因为只要发送的 JSON 是正确的并且 JPA 实体配置是正确的。理想情况下,我不想处理 Hibernate 的特殊性。
你在使用 PATCH 和 PUT 吗?
在 Spring 数据剩余的情况下,调用 PUT will replace your resource completely (and as I understand, create a new, untracked collection), whereas PATCH 只会部分更新您的实体。
在你的情况下,我会说使用 PATCH 是正确的调用,根据我的经验,有时可以解决这个问题。