Spring boot / Spring data jpa - как обновить связанный объект?

У меня есть следующие лица:

@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);

где profileRepository - это экземпляр класса ProfileRepository :

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

который является интерфейсом spring-data-jpa .

Но каждый раз после такого обновления он обновляет таблицу profile но добавляет новую строку в таблицу profile_contacts (таблицу, которая соответствует сущности ProfileContacts ) вместо обновления существующих. Как я могу добиться обновления?

Всего 4 ответа


Согласно вашей структуре JSON. Да, это создаст новую запись в profileContacts каждый раз.

Проблема каждый раз, когда при сохранении сущности profile вы передаете "id": 1 что означает, что Hibernate может идентифицировать сущность по этому значению id (первичному ключу), но для сопоставления profileContacts вы не отправляете id , поэтому Hibernate, учитывая, что у него есть новая сущность каждый раз.

Чтобы обновить свой profileContacts обязательно передайте его идентификатор.

Пример:

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

Ну, это ожидаемое поведение.

Вы не говорите Hibernate, чтобы обновить profileContacts .

Чтобы инфраструктура могла обновлять его, вам необходимо отправить первичный ключ profileContact который в вашем случае является ProfileContacts#id .

Что-то вроде этого:

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

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, "description": "a update", "profileContacts": { "id": 1, "firstName": "John", "lastName ":" Доу "}}


Хорошо, я вижу проблему. Как отметил @Matheus Cirillo, вы должны указать hibernate для обновления строки.

Теперь, как вы говорите Hibernate для обновления строки - путем предоставления первичного ключа существующей строки.

Но создания объекта с набором первичного ключа недостаточно. Вам необходимо, чтобы этот класс сущностей был присоединен к менеджеру сущностей и контексту постоянства.

Вы можете иметь что-то вроде

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

Надеюсь, это поможет.


Есть идеи?

10000