英文:
Spring Data JPA data duplication
问题
以下是翻译好的部分:
我有以下的项目结构:
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@OneToMany(mappedBy = "user", fetch = FetchType.EAGER)
private List<TaskCard> taskCards;
}
public class TaskCard {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@OneToMany(mappedBy = "taskCard", fetch = FetchType.LAZY)
private List<Task> tasks;
@ManyToOne(cascade = CascadeType.ALL)
@JoinColumn(name = "user_id")
private User user;
}
public class Task {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@ManyToOne(cascade = CascadeType.ALL)
@JoinColumn(name = "task_card_id")
private TaskCard taskCard;
}
问题出在这里。当访问POST任务控制器方法以创建新任务时,我执行以下操作:
@PostMapping
public Task createTask(@CurrentUser UserPrincipal userPrincipal, @PathVariable("cardId") Long cardId, @RequestBody Task task) {
User user = userService.findUserById(userPrincipal.getId());
task.setTaskCard(user.getTaskCards().stream()
.filter(card -> card.getId().equals(cardId))
.findFirst()
.get());
return taskService.saveTask(task);
}
User Principal 是当前用户。但它仅存储元数据,我从中获取id以在用户数据库中查找。在这里值得注意的是,我在数据库中查找用户,从中获取任务卡并查找所需的卡片。然后,我将此值分配给新任务,以使其属于该卡片。之后,我将其保存在存储库中。但问题是,在此之后,为 User 实例创建了另一个相同的卡片,因此每次我添加任务时,我都会得到任务卡的另一个副本,而这些副本在用户中。问题是我不知道它们是如何出现或者如何保存的。在数据库中,一切都井然有序,数据没有重复,但是为什么在从数据库中提取时,我得到的卡片并不是 'user_id' 等于该用户的卡片,而是包括所有卡片,还有重复的卡片?这甚至听起来是难以理解的。我附上了数据库的截图:
如你所见,在数据库中一切都井然有序,没有重复,但在调试中发生了以下情况:
我添加了5个任务,最后得到了5个卡片的副本,尽管应该只有一个。正如你所看到的,问题的根源在于“本地”用户实例,它保存了重复的内容。如何解决这个问题?
英文:
I have the following project structure:
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@OneToMany(mappedBy = "user", fetch = FetchType.EAGER)
private List<TaskCard> taskCards;
}
public class TaskCard {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@OneToMany(mappedBy = "taskCard", fetch = FetchType.LAZY)
private List<Task> tasks;
@ManyToOne(cascade = CascadeType.ALL)
@JoinColumn(name = "user_id")
private User user;
}
public class Task {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@ManyToOne(cascade = CascadeType.ALL)
@JoinColumn(name = "task_card_id")
private TaskCard taskCard;
}
And the problem consists here in what. When accessing the POST Task Controller method to create a new task I do the following:
@PostMapping
public Task createTask(@CurrentUser UserPrincipal userPrincipal, @PathVariable("cardId") Long cardId, @RequestBody Task task) {
User user = userService.findUserById(userPrincipal.getId());
task.setTaskCard(user.getTaskCards().stream()
.filter(card -> card.getId().equals(cardId))
.findFirst()
.get());
return taskService.saveTask(task);
}
User Principal is the current user. But it just stores metadata and I take the id from it to find it in the user's database. Here it is worth noting that I am looking for a user in the database and from it I get taskcards and look for the desired card. After that, I assign this value to the new tosk so that it belongs to this card. After that, I save it in the repository. But the problem is that after this, another identical card is created for the User instance, so every time I add a task, I get another copy of the task cards that are in the user. The problem is that I have no idea how they get there or how they are saved. In the database, I have everything in order, the data is not duplicated, but why then when extracting from the database, I do not get the cards that have 'user_id' equal to this user, but everything in a row along with duplicates? It even sounds incomprehensible. I attach screenshots of what my database looks like:
This is task cards
This is tasks
As you can see in the database everything is in order, there is no duplication, but here's what happens in debug:
I added 5 tasks and in the end I got 5 duplicates of the card, although it should only be one. As you can see, the whole problem is in the "local" user instance, which stores duplicates. How do I fix this?
答案1
得分: 0
你现在可能正在联合获取集合,当您在模型中使用List
时,可能会发生这种情况。我建议您改用Set
,即private Set<Task> tasks;
。
英文:
You are probably join fetching the collections and this is what can happen when you use a List
in your model. I suggest you use a Set
instead i.e. private Set<Task> tasks;
专注分享java语言的经验与见解,让所有开发者获益!
评论