Столбцы однонаправленного внешнего ключа не обновляются при сохранении. ⇐ JAVA

Программисты JAVA общаются здесь
Anonymous
Столбцы однонаправленного внешнего ключа не обновляются при сохранении.

Сообщение Anonymous »

У меня возникли проблемы с обновлением полей однонаправленного внешнего ключа для существующих объектов. Клиент отправляет запрос PUT с полными данными объекта (включая родительские и дочерние объекты), но при сохранении обновляются только примитивные значения, а ссылки на связанные объекты — нет.

Я хотел бы знать, если мне не хватает аннотации или конфигурации, или мне нужно реализовать эту функциональность самостоятельно, и если да, то как. Я спрашиваю, потому что существующий код предполагает, что это должно работать "из коробки".
Для справки: у меня есть старая база кода, которая недавно была обновлена ​​с
  • Spring Boot: с 2.1.3 по 3.3.1
  • Спящий режим: с 5.4.1 по 6.5.2.Окончательная версия
    У меня есть следующие упрощенные объекты:

    Код: Выделить всё

    @Data
    @Entity
    @Audited
    @EqualsAndHashCode(callSuper = true)
    @Table(name = "PERSON")
    // The listener listens for PrePersist and PreUpdate, but does not touch the problematic fields.
    @EntityListeners(PersonListener.class)
    public class Person {
    @Id
    @Column(name = "id", nullable = false, insertable = false, updatable = false)
    private Long id;
    
    @Column(name = "name", nullable = false)
    private String name;
    
    @ManyToOne(targetEntity = Country.class, fetch = FetchType.LAZY)
    @JoinColumn(name = "birth_country_id", referencedColumnName = "id", foreignKey = @ForeignKey(name = "fk_birth_country"))
    @RestResource(exported = false)
    private Country birthCountry;
    
    @ManyToMany(targetEntity = Address.class, cascade = {CascadeType.DETACH, CascadeType.MERGE, CascadeType.PERSIST, CascadeType.REFRESH}, fetch = FetchType.LAZY)
    @JoinTable(name = "person_address",
    joinColumns = @JoinColumn(name = "person_id"),
    inverseJoinColumns = @JoinColumn(name = "address_id")
    )
    private List addresses = new ArrayList();
    // Other fields omitted for brevity.
    }
    
    И страна рождения, и адреса имели аннотацию @LazyToOne(value = LazyToOneOption.NO_PROXY).

    Код: Выделить всё

    @Data
    @Entity
    @Audited
    @Table(name = "COUNTRY")
    @EntityListeners(AuditingEntityListener.class)
    public class Country implements Serializable {
    @Id
    @Column(name = "id", nullable = false, length = 19)
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    
    @Column(name = "name", nullable = false)
    private String name;
    }
    

    Код: Выделить всё

    @Data
    @Entity
    @Audited
    @Table(name = "ADDRESS")
    @EqualsAndHashCode(callSuper = true)
    public class Address {
    @Id
    @Column(name = "id", nullable = false)
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    
    @ManyToOne(targetEntity = Country.class, fetch = FetchType.LAZY, optional = false)
    @JoinColumn(name = "country_id", referencedColumnName = "id", nullable = false, foreignKey = @ForeignKey(name = "fk_country"))
    private Country country;
    
    @Column(name="street", nullable = false)
    private String street;
    }
    
    И для человека, и для страны у меня есть простой репозиторий отдыха, как показано ниже. Адрес не имеет репозитория.

    Код: Выделить всё

    @RepositoryRestResource(collectionResourceRel = "person", path = "person")
    public interface PersonRepository extends JpaRepository
     {
    }
    
    
    Например, у меня есть следующий человек:

    Код: Выделить всё

    {
    "id": 1,
    "name": "John Smith",
    "birthCountry": {
    "id": 10,
    "name": "United States"
    },
    "addresses": [{
    "id": 100,
    "country": {
    "id": 10,
    "name": "United States"
    },
    "name": "Wall Street"
    }]
    }
    
    Я получаю следующий json от клиента через PUT, когда пользователь выбирает новую страну и изменяет адрес. Вот какой я ожидал бы получить конечный результат:

    Код: Выделить всё

    {
    "id": 1,
    "name": "Oliver Smith",
    "birthCountry": {
    "id": 11,
    "name": "Canada"
    },
    "addresses": [{
    "id": 100,
    "country": {
    "id": 12,
    "name": "Mexico"
    },
    "name": "Avenida Francisco I. Madero"
    }]
    }
    

    Код: Выделить всё

    SimpleJpaRepository.save
    вызывается, но объединяются только изменения примитивных значений. Это конечный результат в базе данных:

    Код: Выделить всё

    {
    "id": 1,
    "name": "Oliver Smith",
    "birthCountry": {
    "id": 10,
    "name": "United States"
    },
    "addresses": [{
    "id": 100,
    "country": {
    "id": 10,
    "name": "United States"
    },
    "name": "Avenida Francisco I. Madero"
    }]
    }
    
    В журнале отладки sql я вижу, что оператор обновления, сгенерированный Hibernate, содержит id=10 вместо того, что я получил от клиента.

    Как ни странно, когда я отлаживаю метод SimpleJpaRepository.save в IntelliJ и смотрю на сущность Person в представлении отладчика, я вижу новые примитивные значения в связанных сущностях с id=null. Однако если я вычисляю выражение, запрашивающее то же самое, фрагмент кода возвращает старые значения.

    Подробнее здесь: https://stackoverflow.com/questions/791 ... ed-on-save

Вернуться в «JAVA»