下面是预期的表结构:
Users -> user_id (PK)
RoleA -> role_a_id (PK)
RoleB -> role_b_id (PK)
User_Roles -> user_id (FK), role_a_id (FK), role_a_id (FK)
下面是实体类:
@Table(name = "users")
@Entity
public class Users {
public int getUserId() {
return userId;
}
public void setUserId(int userId) {
this.userId = userId;
}
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name = "user_id")
private int userId;
@OneToMany(cascade = CascadeType.ALL)
@JoinTable(
name = "user_roles",
joinColumns = @JoinColumn(name = "user_id"),
inverseJoinColumns = @JoinColumn(name = "role_a_id"))
Set<RoleA> rolesA;
@OneToOne(cascade = CascadeType.ALL)
@JoinTable(
name = "user_roles",
joinColumns = @JoinColumn(name = "user_id"),
inverseJoinColumns = @JoinColumn(name = "role_b_id"))
RoleB rolesB;
public Set<RoleA> getRolesA() {
return rolesA;
}
public void setRolesA(Set<RoleA> rolesA) {
this.rolesA = rolesA;
}
public RoleB getRolesB() {
return rolesB;
}
public void setRolesB(RoleB rolesB) {
this.rolesB = rolesB;
}
}
@Table(name = "role_a")
@Entity
public class RoleA {
public int getRoleAId() {
return roleAId;
}
public void setRoleAId(int roleAId) {
this.roleAId = roleAId;
}
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name = "role_a_id")
private int roleAId;
}
@Table(name = "role_b")
@Entity
public class RoleB {
public int getRoleBId() {
return roleBId;
}
public void setRoleBId(int roleBId) {
this.roleBId = roleBId;
}
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name = "role_b_id")
private int roleBId;
}
插入数据的代码:
RoleA roleA = new RoleA();
roleA.setRoleAId(1);
Set<RoleA> rolesA = new HashSet<>();
rolesA.add(roleA);
RoleB roleB = new RoleB();
roleB.setRoleBId(2);
Users user = new Users();
user.setUserId(10);
user.setRolesA(rolesA);
user.setRolesB(roleB);
userDAO.addUser(user);
启动服务器时,所有表均按预期方式创建,但是一旦尝试按上述方法插入数据,则出现以下错误:
2020-04-01 17:14:35.203 DEBUG 30244 --- [p-nio-80-exec-2] org.hibernate.SQL : insert into users (user_id) values (?)
2020-04-01 17:14:35.206 TRACE 30244 --- [p-nio-80-exec-2] o.h.type.descriptor.sql.BasicBinder : binding parameter [1] as [INTEGER] - [95]
2020-04-01 17:14:35.249 DEBUG 30244 --- [p-nio-80-exec-2] org.hibernate.SQL : insert into user_roles (role_b_id, user_id) values (?, ?)
2020-04-01 17:14:35.250 TRACE 30244 --- [p-nio-80-exec-2] o.h.type.descriptor.sql.BasicBinder : binding parameter [1] as [INTEGER] - [2]
2020-04-01 17:14:35.251 TRACE 30244 --- [p-nio-80-exec-2] o.h.type.descriptor.sql.BasicBinder : binding parameter [2] as [INTEGER] - [95]
2020-04-01 17:14:35.310 WARN 30244 --- [p-nio-80-exec-2] o.h.engine.jdbc.spi.SqlExceptionHelper : SQL Error: 0, SQLState: 23502
2020-04-01 17:14:35.311 ERROR 30244 --- [p-nio-80-exec-2] o.h.engine.jdbc.spi.SqlExceptionHelper : ERROR: null value in column "role_a_id" violates not-null constraint
Detail: Failing row contains (2, 95, null).
2020-04-01 17:14:35.393 DEBUG 30244 --- [p-nio-80-exec-2] c.h.refoearn.controller.UserController : DataIntegrityViolationException while adding user: could not execute statement; SQL [n/a]; constraint [role_a_id]; nested exception is org.hibernate.exception.ConstraintViolationException: could not execute statement
根据User_Roles的日志插入语句,未考虑将role_a_id插入并声明为非null,则抛出异常。
Can someone please suggest the root cause why role_a_id is not being taken care while insertion in User_Roles ?
What is the missing piece stopping it to happen ?
Any other suggestion to fulfill the requirement if shared approach is not correct ?
似乎在意图和执行方面可能存在一些差距。 User_Roles
表的确切目的尚不清楚。该表保持着什么关系?是否试图将Users
表与
RoleA
RoleB
RoleA
和RoleB
均>如果是第一种情况,则role_b_id
不应该存在。如果是第二种情况,则role_a_id
不应该存在。
对于第三种情况,您可能需要重新考虑您的设计。考虑一下您想定义什么关系,即以下任一情况都可能适用
RoleA
和RoleB
都相关,但是RoleA
和RoleB
不相互依赖。RoleA
和RoleB
都相关,并且RoleA
和RoleB
相互依赖。[通过查看Users
类,因为它与OneToOne
具有RoleB
关系,我的第一个猜测是,这是RoleA
和RoleB
彼此不依赖的第一点。考虑到您应该完全删除role_b_id
表中的User_Roles
列,并将其直接添加为Users
表的一部分,或者为其创建其他表。
经过分析和不同的建议,我发现如果我们将User_Roles表的两列视为主键,它们将具有冗余数据。从数据库规范化的角度来看,这将是糟糕的设计。如果这三列都是唯一的并且充当主键,那么我看不到该表的任何特定用途。