#java #spring #hibernate #jpa #crud
#java #весна #спящий режим #jpa #crud
Вопрос:
У меня есть 2 класса (сопоставление ОДНОГО со МНОГИМИ).
Родительский класс:
@Entity
@Table(name = "parent")
public class Parent{
@Id
private int ParentId;
@OneToMany(cascade=CascadeType.ALL, mappedBy = "parent")
private List<Child> childEntities;
Дочерний класс:
@Entity
@Table(name = "child")
public class Child{
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int childId;
@ManyToOne(cascade={CascadeType.PERSIST, CascadeType.DETACH, CascadeType.REFRESH, CascadeType.MERGE})
@JoinColumn(name="parent_id")
private Parent parent;
Когда я хочу сохранить родительский объект, сделайте базу данных с помощью parentRepository.save (parent), все правильно. Родительский и дочерний сохраняются в базе данных. Проблема в том, что когда я хочу выполнить parentRepository.save(parent) для родителя, который уже находится в базе данных (JPA выполнит обновление — обновит родительскую таблицу, но в дочернюю таблицу вставит новые строки). Родительская таблица правильная, но в дочерней таблице у меня повторяющиеся значения. Первичный ключ в дочернем элементе является ПОСЛЕДОВАТЕЛЬНЫМ (я использую Postgres db).
Допустим, у меня пустая база данных, и у меня есть эти две строки кода:
parentRepository.save(родительский);
parentRepository.save(родительский);
После этих двух строк у меня будет одна строка в родительской таблице в базе данных, но каждый из его дочерних элементов находится в дочерней таблице дважды.
Комментарии:
1. что, если вы удалите все «каскадные» атрибуты из аннотаций? будет ли эта проблема по-прежнему присутствовать?
2. Я удалил «cascade = CascadeType.ALL» из родительского. Он сохранял данные только в родительской таблице, но не в дочерней таблице (БД была пустой перед вставкой).
Ответ №1:
Учитывая, что вы используете @GeneratedValue
, идентификатор дочернего объекта будет сгенерирован sava
при первом вызове.
Если вы проверите документацию по методу сохранения, вы увидите, что он возвращает новый экземпляр сохраненного вами объекта.
Этот новый экземпляр содержит родительский объект с дочерними объектами с идентификаторами, сгенерированными spring для этих дочерних объектов.
Еще одно важное изменение, которое вам нужно сделать, это использовать типы оболочек вместо примитивов в атрибутах @Id
, аннотированных с. Оболочки могут содержать null
значение, это важно для spring, чтобы знать, является ли объект новым объектом или объектом, подлежащим обновлению. Для получения дополнительной информации проверьте документы spring-data-jpa.
Проблема с вашим кодом заключается, во-первых, в том, что вы используете атрибуты примитивного типа, аннотированные @Id
(измените его на типы оболочек), а во-вторых, предполагается, что вы должны использовать возвращаемый объект из save
метода для дальнейших операций.