休眠 - 1:N - 保存子项时复制父项

Hibernate - 1:N - The parent is duplicated upon saving the child

GitHub repo if needed, Maven web project (pom.xml), SQL script under resources directory.

我知道这是我的错,问题是我一整天都没能解决它,这可能是一些简单的事情,我无法理解,也请忽略有关 [=78 的关系=] 名称和列,这是一个示例项目来显示问题。


预期:

沿其父关系存储新子项(子项有一列),而无需再次存储父项。


错误:

CascadeType.ALL 导致父对象重复,但试图删除它以使用其他类型抛出:java.sql.SQLIntegrityConstraintViolationException: 列 'user_id' 不能为 null

列 'user_id' 是子 table 中存储父关系的列的名称。


我会跳过一些注释,这样就不会变成代码墙


用户实体

private Long id;
private String name;

@OneToMany(mappedBy = "user", fetch = FetchType.LAZY, cascade = {
        CascadeType.DETACH, CascadeType.MERGE, CascadeType.REFRESH})
private List<Username> usernameList = new ArrayList<>();

用户名实体

private Long id;
private String username;

@ManyToOne(fetch = FetchType.EAGER, cascade = CascadeType.ALL)
@JoinColumn(name = "user_id")
private User user;

同样,使用除 CascadeType.All 之外的任何内容都会因某种原因引发错误


UsernameDAO这是用于存储子用户名的方法,它与父用户用户名重复

Session session = factory.getCurrentSession();
session.save(username);

用户名服务

usernameDAO.save(username);

我认为您在对象用户名中分配对象用户的方式不正确。如果您正在做这样的事情:

User user = new User();
user.set(... // set your attributes

Username username = new Username();
username.set(user);

现在,如果您保存 username,hibernate 将在数据库中为 user 创建一个条目,因为您创建 user 的方式是使用 new关键字,这将在数据库中创建一个新条目。

如果您不想为 user 创建一个新条目,那么您将不得不从数据库中加载该实体,因此您应该在您的服务中添加一个新方法 class User 这将 return 你是一个给定用户 ID 的用户。

例如:

User user = userService.getUser(10);

Username username = new Username();
username.set(user);

现在当您保存 username 时,不会在 table User 中创建新条目。这就是休眠的工作方式。我们必须加载实体,然后对其进行操作并保存。 new 关键字将创建一个新条目,即使实体的 ID(数据库中的主键)相同。

如果回答自己的问题有误,请告诉我,所以我只删除它。

问题出在前端,我的 Spring 表单中有以下内容:

<form:select path="user" items="${listUsers}" />

什么时候应该

<form:select path="user.id" items="${listUsers}" itemValue="id"/>

1) 如果未指定 itemValue Spring 将从 toString.

中获取值

2)使用id字段(绑定实体)作为itemValue和关系字段id作为路径

3) 您不一定要删除 ClassType.PERSIST 以避免重复,只要您的实体受其唯一标识符(如id), 否则 hibernate 会将其视为新条目。