休眠 - 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 会将其视为新条目。
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 会将其视为新条目。