Сохранение в базу данных создает несколько записей

Я пишу приложение, которое управляет задачами и связанными с ними заметками. Это приложение Spring Boot, которое использует Vaadin для пользовательского интерфейса и (в настоящее время) базу данных H2 на серверной части, доступ к которой осуществляется через Hibernate.

Приложение состоит из главной страницы, на которой отображаются задачи. Нажатие на задачу позволяет просмотреть подробности, а также кнопку для перехода на другую страницу, чтобы разрешить просмотр и редактирование связанных примечаний к задаче.

Проект можно найти на github по адресу https://github.com/jgagnon44/tasks-app. Я также могу размещать фрагменты кода здесь, хотя я не совсем уверен, что я должен включать. Комментарий, чтобы запросить предметы.

Я вижу поведение, которое не могу объяснить. Когда я нахожусь в представлении списка заметок и добавляю новую заметку, сохраняю ее, добавляю другую и сохраняю ее, я обнаруживаю, что первая заметка была продублирована. Дубликат имеет отметку времени, близкую к отметке времени второй сохраненной заметки. Если бы я добавил третью новую заметку, на этот раз первая и вторая заметки будут продублированы, в результате чего я только что добавил 3 первых заметки, 2 вторых заметки и одну третью заметку.

Я добавил операторы отладки в критические точки кода и распечатываю объекты, задействованные в этих точках.

Я также включил журнал с аннотациями ниже, чтобы проиллюстрировать некоторые из происходящего.

Может ли кто-нибудь дать мне представление о том, что происходит и что мне нужно сделать, чтобы исправить проблему?

Стенограмма журнала:

NOTE: Task-1 has two existing TaskNote items associated with it (note-1 and note-2).

>>>>> Main page.
>>>>> Select Task-1 in grid.
>>>>> Click Edit Notes button.

[INFO ] 2021-04-14 15:02:25.340 com.fossfloors.taskapp.ui.view.NotesListView.refresh(NotesListView.java:100) - PARENT: null
[INFO ] 2021-04-14 15:02:25.358 com.fossfloors.taskapp.ui.view.NotesListView.refresh(NotesListView.java:100) - PARENT: Task [hashcode=-523436836, title=Task-1, description=null, type=RECURRING, state=OPEN, priority=HIGH, notes=[TaskNote [hashCode=-331664091, note=note-1], TaskNote [hashCode=-823479065, note=note-2]], dateClosed=null, dateDue=null, dateStarted=null, dateCompleted=null]
[INFO ] 2021-04-14 15:02:25.361 com.fossfloors.taskapp.ui.view.NotesListView.lambda$7(NotesListView.java:104) - NOTES: [TaskNote [hashCode=-331664091, note=note-1], TaskNote [hashCode=-823479065, note=note-2]]

>>>>> Notes List page.
>>>>> Click Add button.
>>>>> Enter note 3.
>>>>> Click Save button.
>>>>> Note 3 appears in notes list.

[INFO ] 2021-04-14 15:03:05.709 com.fossfloors.taskapp.ui.view.NotesListView.saveNote(NotesListView.java:159) - PARENT: Task [hashcode=-523436836, title=Task-1, description=null, type=RECURRING, state=OPEN, priority=HIGH, notes=[TaskNote [hashCode=-331664091, note=note-1], TaskNote [hashCode=-823479065, note=note-2]], dateClosed=null, dateDue=null, dateStarted=null, dateCompleted=null]
[INFO ] 2021-04-14 15:03:05.709 com.fossfloors.taskapp.ui.view.NotesListView.saveNote(NotesListView.java:160) - NOTE: TaskNote [hashCode=1422869202, note=Note 3]
[INFO ] 2021-04-14 15:03:05.731 com.fossfloors.taskapp.ui.view.NotesListView.refresh(NotesListView.java:100) - PARENT: Task [hashcode=-523436836, title=Task-1, description=null, type=RECURRING, state=OPEN, priority=HIGH, notes=[TaskNote [hashCode=-331664091, note=note-1], TaskNote [hashCode=-823479065, note=note-2], TaskNote [hashCode=1422869202, note=Note 3]], dateClosed=null, dateDue=null, dateStarted=null, dateCompleted=null]
[INFO ] 2021-04-14 15:03:05.735 com.fossfloors.taskapp.ui.view.NotesListView.lambda$7(NotesListView.java:104) - NOTES: [TaskNote [hashCode=-331664091, note=note-1], TaskNote [hashCode=-823479065, note=note-2], TaskNote [hashCode=333570519, note=Note 3]]

>>>>> Click Add button.
>>>>> Enter note 4.
>>>>> Click Save button.
>>>>> Note 4 appears in notes list. Notice that a second note 3 appears with a similar timestamp as note 4.

[INFO ] 2021-04-14 15:03:27.617 com.fossfloors.taskapp.ui.view.NotesListView.saveNote(NotesListView.java:159) - PARENT: Task [hashcode=-523436836, title=Task-1, description=null, type=RECURRING, state=OPEN, priority=HIGH, notes=[TaskNote [hashCode=-331664091, note=note-1], TaskNote [hashCode=-823479065, note=note-2], TaskNote [hashCode=1422869202, note=Note 3]], dateClosed=null, dateDue=null, dateStarted=null, dateCompleted=null]
[INFO ] 2021-04-14 15:03:27.618 com.fossfloors.taskapp.ui.view.NotesListView.saveNote(NotesListView.java:160) - NOTE: TaskNote [hashCode=1422869203, note=Note 4]
[INFO ] 2021-04-14 15:03:27.628 com.fossfloors.taskapp.ui.view.NotesListView.refresh(NotesListView.java:100) - PARENT: Task [hashcode=-523436836, title=Task-1, description=null, type=RECURRING, state=OPEN, priority=HIGH, notes=[TaskNote [hashCode=-331664091, note=note-1], TaskNote [hashCode=-823479065, note=note-2], TaskNote [hashCode=1422869202, note=Note 3], TaskNote [hashCode=1422869203, note=Note 4]], dateClosed=null, dateDue=null, dateStarted=null, dateCompleted=null]
[INFO ] 2021-04-14 15:03:27.634 com.fossfloors.taskapp.ui.view.NotesListView.lambda$7(NotesListView.java:104) - NOTES: [TaskNote [hashCode=-331664091, note=note-1], TaskNote [hashCode=-823479065, note=note-2], TaskNote [hashCode=333570519, note=Note 3], TaskNote [hashCode=-1887191816, note=Note 3], TaskNote [hashCode=-1221858374, note=Note 4]]

>>>>> Click Back button.
>>>>> Main page.
>>>>> Select Task-1 in grid.
>>>>> Click Edit Notes button. There are five notes.

[INFO ] 2021-04-14 15:03:44.434 com.fossfloors.taskapp.ui.view.NotesListView.refresh(NotesListView.java:100) - PARENT: null
[INFO ] 2021-04-14 15:03:44.439 com.fossfloors.taskapp.ui.view.NotesListView.refresh(NotesListView.java:100) - PARENT: Task [hashcode=-523436836, title=Task-1, description=null, type=RECURRING, state=OPEN, priority=HIGH, notes=[TaskNote [hashCode=-331664091, note=note-1], TaskNote [hashCode=-823479065, note=note-2], TaskNote [hashCode=333570519, note=Note 3], TaskNote [hashCode=-1887191816, note=Note 3], TaskNote [hashCode=-1221858374, note=Note 4]], dateClosed=null, dateDue=null, dateStarted=null, dateCompleted=null]
[INFO ] 2021-04-14 15:03:44.444 com.fossfloors.taskapp.ui.view.NotesListView.lambda$7(NotesListView.java:104) - NOTES: [TaskNote [hashCode=-331664091, note=note-1], TaskNote [hashCode=-823479065, note=note-2], TaskNote [hashCode=333570519, note=Note 3], TaskNote [hashCode=-1887191816, note=Note 3], TaskNote [hashCode=-1221858374, note=Note 4]]

person Joseph Gagnon    schedule 14.04.2021    source источник
comment
Похоже, вы добавляете их в List или другой Collection и каждый раз сохраняете всю коллекцию. Но у нас нет кода, так что это лучшее предположение   -  person DCTID    schedule 15.04.2021


Ответы (1)


Я заглянул в ваш git и думаю, проблема в том, что вы сохраняете Task, который имеет каскадное отношение к списку TaskNote, но вы передаете устаревший экземпляр Task, который не имеет всех TaskNotes, который вы ранее сохранили.

Убедитесь, что вы обновили parentTask после сохранения, чтобы он отслеживал свои текущие (сохраненные!) Заметки о задачах. Это должно гарантировать, что отношения в БД не будут дублироваться при последующих сохранениях. Вы уже выполнили refresh() в представлении после сохранения, НО по-прежнему забыли обновить там экземпляр parentTask.
Вот как можно улучшить ваш метод refresh:

private void refresh() {
    logger.info("PARENT: {}", parentTask);
    if (parentTask != null) {
      Optional<Task> optTask = taskService.findById(parentTask.getId());
      optTask.ifPresent(task -> {
        logger.info("NOTES: {}", task.getNotes());
        this.parentTask = task;    // UPDATE PARENTTASK INSTANCE HERE!!
        grid.setItems(task.getNotes());
      });
    } else {
      grid.setItems();
    }
  }
person kscherrer    schedule 15.04.2021