保存到数据库会创建多个条目

问题描述

我正在编写一个管理任务和相关笔记的应用程序。这是一个 Spring Boot 应用程序,它使用 Vaadin 作为 UI 和(当前)后端上的 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-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,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,note=note-2],TaskNote [hashCode=1422869202,note=Note 3]],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,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,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,note=Note 3],TaskNote [hashCode=1422869203,note=Note 4]],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,TaskNote [hashCode=-1887191816,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,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 4]]

解决方法

我偷看了你的 git,我认为问题在于你保存了一个与 TaskList 有级联关系的 TaskNote,但是你传递一个过时的 Task 实例,该实例没有您之前保存的所有 TaskNotes

确保在保存后更新 parentTask,以便跟踪它的当前(持久化!)TaskNotes。这应该确保它不会在后续保存时复制数据库中的关系。保存后您已经在视图上执行了 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();
    }
  }

相关问答

错误1:Request method ‘DELETE‘ not supported 错误还原:...
错误1:启动docker镜像时报错:Error response from daemon:...
错误1:private field ‘xxx‘ is never assigned 按Alt...
报错如下,通过源不能下载,最后警告pip需升级版本 Requirem...