Невозможно сохранить объект Json с данными Spring, имеющими отношение @OneToMany

#java #json #spring #hibernate #spring-data

#java #json #spring #переход в спящий режим #spring-данные

Вопрос:

У меня есть объект с именем Sale , который имеет список объектов SaleData , я установил однонаправленную @OneToMany связь между этими двумя. Теперь я столкнулся с проблемами при выполнении операций CRUD с моим объектом Sale.

CascadeType установлено значение ALL .

 @Entity
@Table(name = "sale")
public class Sale extends BaseEntity {

  @OneToOne(cascade = CascadeType.DETACH)
  private Client client;

  @OneToMany(cascade = {CascadeType.ALL}) // <--
  @JoinColumn(name = "sale_id", nullable = false)
  private List<SaleData> saleData = new ArrayList<>();
}
  

Сохранение (ПУБЛИКАЦИЯ) и удаление работают. Проблема в том, что при отправке для обновления мой JSON, отправленный с контроллера Angular, выглядит следующим образом:

 {"id": 1, "client": {
    "id": 1,
    "firstName": "Test",
    "lastName": "Client"
}, "saleData": [
    {
        "id": 1,
        "employee": {
            "id": 1,
            "firstName": "Herp",
            "lastName": "Derp"
        }
    },
    {
        "id": 2,
        "employee": {
            "id": 1,
            "firstName": "John",
            "lastName": "Smith"
        }
    }
]}
  

Вызов обновления из службы Spring выдает:

 org.hibernate.PersistentObjectException: detached entity passed to persist: app.sales.SaleData
  

Реализация сервиса

   @Override
  @Transactional(rollbackFor = SaleNotFoundException.class)
  public Sale update(@NotNull SaleDTO updated) {
    Sale sale = repository.findOne(updated.getId());

    if (sale == null)
      throw new SaleNotFoundException("Sale not found");

    return transformSaleObject(sale, updated);
  }
  

Как я понимаю, cascade ALL не отключает объект sale, потому что во втором сценарии, где я заменяю тип на любую комбинацию …

 @OneToMany(cascade = {CascadeType.PERSIST, CascadeType.REMOVE, CascadeType.DETACH})
  

.. тогда Обновление и удаление работают, но сохранение нового объекта — нет. Я не так часто использовал Hiberate, но, может быть, кто-нибудь знает, что вызывает такое поведение? Это вопрос неправильного определения отношения?

Обновление: Метод transform — это просто это, но в любом случае, похоже, что теперь для меня все решено 🙂

   private Sale transformSaleObject(Sale sale, SaleDTO dto) {
    sale.setClient(dto.getClient());
    sale.setSaleData(dto.getSaleData());
    sale.setService(dto.getService());
    sale.setHours(dto.getHours());
    sale.setPrice(dto.getPrice());
    sale.setSaleStatus(dto.getSaleStatus());
    sale.setSaleDate(dto.getSaleDate());
    return sale;
  }
  

Я изменил свой метод обновления следующим образом:

   public Sale update(@NotNull SaleDTO updated) {
    Sale sale = repository.findOne(updated.getId());

    if (sale == null)
      throw new SaleNotFoundException("Sale not found");

    transformSaleObject(sale, updated);

    return repository.saveAndFlush(sale);
  }
  

Комментарии:

1. Ваша ошибка означает, что вы пытаетесь сохранить тот же объект (то есть с идентичным идентификатором) во второй раз. Вместо сохранения вы можете выполнить обновление, только если ваша сущность отсоединена (не постоянна). Для удобства вы можете использовать метод orh.hibernate.Session.saveOrUpdate . Вы можете найти полезным этот документ

2. Данные Spring предназначены только save(entity) для сохранения, и вы обновляете их, находя объект по идентификатору и изменяя значения, которые хотите обновить, после этого вы не вызываете никаких других методов, но после завершения транзакции эти изменения фиксируются.

3. Может быть и так. Попробуйте удалить @JoinColumn аннотацию из отношения @OneToMany к saleData коллекции. Вместо этого поместите @JoinColumn(name = "sale_id", nullable = false) ссылку на продажу внутри SaleData объекта.

4. В однонаправленной связи у меня нет Sale ссылки в моем SaleData классе. Единственная ссылка находится в продаже.

5. Это не рекомендуется. Лучшим вариантом является двунаправленная ассоциация «один ко многим» . Посмотрите, что они говорят об однонаправленном «один ко многим» здесь .