【问题标题】:JPA - update entity with one to many relationship array listJPA - 使用一对多关系数组列表更新实体
【发布时间】:2020-04-04 07:39:57
【问题描述】:

假设我正在更新与帖子具有一对多关系的用户实体

这是更新代码

public User updateUser(Long userid, Userdto userdto) {
    User user = findByTemplatesFooterNo(userid);
    User mappedUser = modelmapper.map(UserDto, User.class);

    user.setName(mappedUser.getName());
    user.setAge(mappedUser.getAge());

    user.getPosts().clear();
    user.getPosts().addAll(mappedUser.getPost());

    userrepository.save(user);
}

这是用户的当前数据

{
  "user_id" : 1,
  "name" : "testname",
  "age" : "testage",
  "posts" : [
       {
            "post_id" : 1,
            "title" : "titlepost",
            "content" : "content"
       },
       {
            "post_id" : 2,
            "title" : "titlepost",
            "content" : "content"
       },
  ]
}

这是我传递的请求正文以更新 ID 为 1 的用户

{
  "name" : "testname",
  "age" : "testage",
  "posts" : [
       {
            "title" : "titlepost",
            "content" : "content"
       }    
  ]
}

我可以成功更新用户并且响应是

{
  "user_id" : 1,
  "name" : "testname",
  "age" : "testage",
  "posts" : [
       {
            "post_id" : 3,
            "title" : "titlepost",
            "content" : "content"
       }    
  ]
}

它取代了所有当前的帖子。我想要的只是附加新的,以便响应变为

{
      "user_id" : 1,
      "name" : "testname",
      "age" : "testage",
      "posts" : [
           {
                "post_id" : 1,
                "title" : "titlepost",
                "content" : "content"
           },
           {
                "post_id" : 2,
                "title" : "titlepost",
                "content" : "content"
           },
           {
                "post_id" : 3,
                "title" : "titlepost",
                "content" : "content"
           },
      ]
}

用户实体

 @OneToMany(
            cascade = CascadeType.ALL,
            orphanRemoval = true,
            fetch = FetchType.LAZY
 )
 @JoinColumn(
            name = "user_id",
            foreignKey = @ForeignKey(name = "fk_post_id"),
            referencedColumnName = "userId"
 )
 private List<Post> post = new ArrayList<>();

【问题讨论】:

  • 您需要通过 id (1) 获取用户,比较并保存整个对象
  • 比较是什么意思?我通过 id 1 获取用户
  • 正确,按 ID 获取用户以获取现有帖子。将现有帖子与收到的帖子进行比较。如果传入的帖子是新的(比较可能说不存在),则将其附加到现有的 List 并再次保存整个用户对象
  • 有什么例子可以开始吗?

标签: java spring-boot jpa spring-data-jpa


【解决方案1】:

您明确调用user.getPosts().clear(),但您对只有新帖子存在感到惊讶?

您还需要注意 userrepository.save(user) 返回合并的结果,您需要从您的方法中返回该结果,以便将最新的表示形式序列化为 JSON。

https://docs.spring.io/spring-data/commons/docs/current/api/org/springframework/data/repository/CrudRepository.html?is-external=true#save-S-

保存给定的实体。 使用返回的实例进行进一步操作 因为保存操作可能已经改变了实体实例 完全。

变化:

public User updateUser(Long userid, Userdto userdto) {
    User user = findByTemplatesFooterNo(userid);
    User mappedUser = modelmapper.map(UserDto, User.class);

    user.setName(mappedUser.getName());
    user.setAge(mappedUser.getAge());

    //user.getPosts().clear(); <-- WHY?
    user.getPosts().addAll(mappedUser.getPost());

    return userrepository.save(user); // <-- return the result of the merge
}

【讨论】:

  • 这个问题是当我在帖子中更新特定 id 时,它不会更新并且会出错,因为帖子将使用相同的 id 保存两次,这就是为什么我需要先清除它?保存前
  • 好的,所以你应该问一个关于这个的问题,而不是你认为的解决方案。 meta.stackexchange.com/questions/66377/what-is-the-xy-problem
【解决方案2】:

user.getPosts().addAll(mappedUser.getPost());

据我所知,Hibernate 建议对一对多关系使用 Collection 接口。 通过这种方式,addAll 不会将现有的帖子元素与新闻合并。 因此,您将在集合中拥有重复的帖子。 addAll 仅在您 100% 确定 mappedUser 仅包含新元素的情况下才有效。但如果不是这样,那么您将需要手动合并或清除以前的集合以避免重复。 不推荐清除收藏。因为clear意味着hibernate会删除所有记录,然后再创建。

只有在您选择 Set like collection 的情况下,您的方式才有效。 但它也不推荐,因为设置需要计算哈希码。要做到这一点,休眠将需要从数据库中获取所有记录。 想象一下,一个用户有 3000 个帖子。然后添加一个新的设置... Hibernate 需要获取所有 3000 个帖子以确保新的帖子是唯一的。

【讨论】:

    猜你喜欢
    • 2016-01-03
    • 1970-01-01
    • 2013-04-25
    • 2021-05-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多