【问题标题】:Spring boot/Spring data jpa - how to update related entity?Spring boot/Spring data jpa - 如何更新相关实体?
【发布时间】:2020-01-15 17:36:26
【问题描述】:

我有以下实体:

@Entity
@Table(name = "profile")
public class Profile {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "id")
    private Long id;

    @OneToOne(cascade = CascadeType.ALL)
    private ProfileContacts profileContacts;

...

}

@Entity
@Table(name = "profile_contacts")
public class ProfileContacts {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "id")
    private Long id;

    @Column(name = "description")
    private String description;

    @Column(name = "first_name")
    private String firstName;

    @Column(name = "last_name")
    private String lastName;

}

我正在尝试通过将此带有更新的 JSON 发送到 REST 控制器来更新它:

{
        "id": 1,
        "description": "an update",
        "profileContacts": {
            "firstName": "John",
            "lastName": "Doe"
        }
 }

所以最后它会调用

profileRepository.save(profile);

其中profileRepositoryProfileRepository 类的实例:

public interface ProfileRepository extends JpaRepository<Profile, Long> {
}

这是spring-data-jpa接口。

但每次更新后,它都会更新profile 表,但会将new 行添加到profile_contacts 表(对应于ProfileContactsentity 的表),而不是更新现有的。 如何实现更新?

【问题讨论】:

  • 你能发布profile对象的内容吗?
  • 增加新行是什么意思?新纪录?
  • @SandeshaJ 我添加了更多信息请看一下
  • @gnanajeyam95 表格的新行。
  • no id or not existing id -> "create", existing id -> "update" (?;) (谈论嵌套的 "profileContacts" (json) 元素)

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


【解决方案1】:

根据您的 JSON 结构。是的,它每次都会创建新的profileContacts 条目。

每次保存 profile 实体时都会出现问题,您传递 "id": 1 这意味着 Hibernate 可以通过此 id 值(主键)识别实体,但对于 profileContacts 映射,您不会发送 id这就是为什么 Hibernate 每次都认为它有一个新实体。

要更新您的 profileContacts 实体,请确保传递它的 id。

例子:

{ 
"id": 1,
 "description": "an update", 
"profileContacts": {
"id" : yourEntityId
 "firstName": "John", 
"lastName": "Doe" 
}
 }

【讨论】:

  • 这是否允许客户端通过简单地传递随机的EntityId 来更新任何个人联系人?
  • 如果随机数与持久化实体 id(数据库条目)匹配,那么它将更新。但我认为可以通过级联来限制这一点。
【解决方案2】:

嗯,这是预期的行为。

你没有告诉休眠更新profileContacts

为了使框架能够更新它,您需要发送 profileContact 的主键 - 在您的情况下是 ProfileContacts#id

类似这样的:

{
  "id": 1,
  "description": "an update",
  "profileContacts": {
    "id": 1
    "firstName": "John",
    "lastName": "Doe"
  }
}

【讨论】:

    【解决方案3】:
    Need to specify the join column in the parent Entity.
    @Entity
    @Table(name = "profile")
    public class Profile {
    
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "id")
    private Long id;
    
    @OneToOne(cascade = CascadeType.ALL)
    **@JoinColumn(name = "id")** //
    private ProfileContacts profileContacts;
    
    ...
    
    }
    Now when you try to save Profile entity it will save the child entity also. 
    

    并且还需要在子实体的 jason 请求中包含 Id { “身份证”:1, “描述”:“更新”, “个人资料联系人”:{ “id”:1, "firstName": "约翰", “姓氏”:“母鹿” } }

    【讨论】:

      【解决方案4】:

      好的,我看到了问题。正如@Matheus Cirillo 指出的那样,您需要告诉休眠更新行。

      现在,你如何告诉休眠更新一行 - 通过提供现有行的主键。

      但是,使用主键集创建一个对象是不够的。您需要将该实体类附加到实体管理器和持久性上下文。

      你可以有类似的东西,

      //This attaches the entity to the entity manager
      ProfileContacts existingProfileContacts = profileContactRepository.getOne(2);
      Profile profile = new Profile();
      ....
      ....
      profile.setProfileContacts(existingProfileContacts);
      profileRepository.save(profile);
      

      我希望这会有所帮助。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2012-08-06
        • 1970-01-01
        • 1970-01-01
        • 2016-12-03
        • 1970-01-01
        • 1970-01-01
        • 2020-07-04
        • 1970-01-01
        相关资源
        最近更新 更多