#java #spring-boot #spring-data-jpa
#java #spring-boot #spring-data-jpa
Вопрос:
Я изо всех сил пытаюсь понять, как использовать Spring Data / JPA для взаимодействия с базой данных. В настоящее время я использую простую базу данных H2 для целей тестирования.
У меня есть основной элемент, Task
, который в дополнение к полям также содержит две коллекции «дочерних» данных: TaskNote
и StateChangeHistory
.
В моем классе обслуживания задач у меня есть @PostConstruct
метод настройки некоторых фиктивных данных и сохранения их в базе данных, чтобы я мог получить и отобразить их позже. Похоже, что Task
сохраняется, но ни один из дочерних элементов не сохраняется. Когда я загружаю данные в представление (или проверяю данные в отладчике), дочерние коллекции всегда пусты.
Что мне нужно сделать, чтобы убедиться, что задача и все ее дочерние элементы сохранены?
Вот часть кода:
Task.java:
@Entity
@NamedEntityGraph(name = "graph.task", attributeNodes = { @NamedAttributeNode("notes") })
public class Task extends AbstractEntity {
@OneToMany(mappedBy = "task")
private List<StateChangeHistory> stateHistory = new ArrayList<>();
@OneToMany(mappedBy = "task")
private List<TaskNote> notes = new ArrayList<>();
...
}
TaskNote.java:
@Entity
public class TaskNote extends AbstractEntity {
@ManyToOne
private Task task;
...
}
TaskRepository.java:
public interface TaskRepository extends JpaRepository<Task, Long> {
@Override
@EntityGraph(attributePaths = { "notes" })
public List<Task> findAll();
}
TaskService.java:
@Service
public class TaskService {
private TaskRepository taskRepository;
public TaskService(TaskRepository taskRepository) {
this.taskRepository = taskRepository;
}
...
@PostConstruct
public void populateTestData() {
if (taskRepository.count() == 0) {
Task task = null;
TaskNote note = null;
// Task 1
task = new Task("Task-1");
task.setPriority(TaskPriority.HIGH);
task.setType(TaskType.RECURRING);
// Note 1
note = new TaskNote();
note.setNote("note-1");
task.getNotes().add(note);
// Note 2
note = new TaskNote();
note.setNote("note-2");
task.getNotes().add(note);
taskRepository.save(task);
// Task 2
taskRepository.save(new Task("Task-2"));
}
}
}
Как вы можете видеть, я создаю объект task и добавляю к нему две заметки, а затем пытаюсь сохранить его. Я предполагаю, что сохранение задачи работает, поскольку я могу заставить их отображаться в моем представлении. Однако список заметок всегда пуст.
Что мне нужно сделать, чтобы сохранить дочерние данные вместе с родительскими?
Комментарии:
1. Решит ли это проблему, если вы добавите атрибут ‘cascade’ в аннотацию @OneToMany? каскад=CascadeType.ALL
Ответ №1:
Как указано в других ответах, вы должны использовать @OneToMany(cascade=CascadeType.ALL)
over Task notes
.
Чтобы заставить код работать, вы должны установить двустороннюю связь сущностей:
Task task = new Task("Task-1");
TaskNote note = new TaskNote();
note.setNote("note-1");
note.setTask(task); // missing in your code
task.getNotes().add(note);
taskRepository.save(task);
Ответ №2:
Существует три способа сохранения статуса объекта с помощью JPA.
- Загрузите объект из базы данных и внесите изменения в его состояние. JPA отслеживает эти изменения и Удаляет их (т. Е. Выполняет DML-инструкции) до завершения транзакции, обычно точно в конце транзакции.
- Создайте объекты и
save
их в репозиторий - Выполните # 2 с другим объектом, который ссылается на ваш объект со ссылкой
cascade=CascadeType.ALL
, аннотированной с. На самом делеMERGE
иPERSIST
достаточно, но я думаю, что если вы каскадируете, вы должны каскадировать все.
Ответ №3:
Решение
Вы можете решить эту проблему, просто добавив cascade= CascadeType.ALL
аннотацию @OneToMany в качестве свойства.