【问题标题】:Spring data rest one to many delete child objectsSpring数据休息一对多删除子对象
【发布时间】:2015-07-06 05:41:12
【问题描述】:

我在团队和玩家之间有一对多的关系,我可以使用以下 JSON 创建一个团队

{
    "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;
}

我做错了什么?当我创建一个包含一群球员的新团队时,杰克逊能够完美地映射一对多关系,但是当我从 Team json 更新/删除球员时,它会失败并出现同样的错误。是否有可能重新创建集合,这就是休眠引发错误的原因,如果是这样,我应该如何修复它?请帮忙

【问题讨论】:

    标签: json spring hibernate spring-data-jpa spring-data-rest


    【解决方案1】:

    您面临的问题来自players 列表的替换。 Hibernate 需要跟踪哪些元素被删除,并在特定列表实现的帮助下完成此操作(据我所知PersistentList)。

    当您或其他人致电setPlayers 时,最有可能出现问题。有效地将列表替换为新实例。

    要解决此问题,您有两种可能性:

    • 避免调用setPlayers 使用getPlayers.remove / add
    • 或修改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
        
    }
    

    【讨论】:

    • 这段代码会去哪里?这个问题是spring-data-rest特有的,有没有spring-data-rest的方式来处理这种情况?
    • 此代码将是 jpa 实体内的设置器。我不知道任何 spring-data-rest 特定的方式。
    • 解决方案是否确保不创建新玩家?
    • 测试了@MartinFrey 给出的方法并且它有效。我涵盖了所有添加、删除、更新的案例,它们都运行良好。创建新 id 并删除已删除的玩家。谢谢。
    • 如果有一种方法可以由 Spring Data Rest 自动处理,那就太好了。等待有人想出这样的方法。
    【解决方案2】:

    您可能是对的,该集合正在被替换。

    我假设有一个 TeamRepository 和一个 PlayerRepository 并且两者都被导出。这意味着Team 响应会公开players 链接,您可以在其中发布应该在团队中的玩家的URI。如果玩家实体还不存在,您首先创建它。这就是 Spring Data REST 的工作方式。

    另外请记住,公开数据库 ID 并不完全是 RESTful。资源的 ID 是它的 URI。

    【讨论】:

      【解决方案3】:

      我在使用 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 的特殊性。

      【讨论】:

        【解决方案4】:

        你在使用 PATCH og PUT 吗?

        在 Spring Data Rest 的情况下,调用 PUT 将完全替换您的资源(据我所知,创建一个新的、未跟踪的集合),而 PATCH 只会部分更新您的实体。

        在你的情况下,我会说使用 PATCH 是正确的调用,根据我的经验,有时可以解决这个问题。

        【讨论】:

          猜你喜欢
          • 2015-07-04
          • 2021-07-23
          • 2012-09-04
          • 2018-08-23
          • 2013-05-25
          • 1970-01-01
          • 1970-01-01
          • 2011-02-13
          相关资源
          最近更新 更多