我有两个表,用户和角色。角色类似于“ ADMIN”,“ MANAGER”,“ USER”。用户可以具有这些角色。因此,在我的Java项目中,我的用户为
@Entity
@Table(name = "users")
public class User {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name = "user_id")
private Integer userId;
@ManyToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
@JoinTable(name = "user_roles", joinColumns = @JoinColumn(name =
"user_id"), inverseJoinColumns = @JoinColumn(name = "role_id"))
private Set<Role> roles;
//other data and getters and setters
}
我的角色课就像
@Entity
@Table(name = "role")
public class Role {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name = "role_id")
private Integer roleId;
@Column(name = "role_name",unique=true)
private String role;
//getters and setters
}
比方说,我已向Roles手动插入了3条记录
INSERT INTO `role` VALUES (1,'ADMIN');
INSERT INTO `role` VALUES (2,'MANAGER');
INSERT INTO `role` VALUES (3,'USER');
现在,我想插入到User表中,以便仅插入user和user_roles(联接表):
例如:
如果我要插入一个userId = 1和role = {ADMIN,MANAGER}的用户,则应该插入user表中的一个条目和user_roles表中的2个条目,例如(1,1)
和(1,2)
。角色表不应插入任何内容。我该如何实现?
我尝试将manytomany更改为onetomany...。此外,我尝试将cascadeType.all更改为CascadeType.MERGE并分离...它们均无法正常工作... 请帮助
//更新:
添加与创建/更新用户相关的代码
public User createUser(UserDto account) {
User newUser = new User();
newUser.setPassword(account.getPassword());
newUser.setUsername(account.getUsername());
Set<Role> roles = new HashSet<Role>();
Role role = roleRepository.findByRole(account.getRole());
if (role != null) {
role.setRole(account.getRole());
roles.add(role);
newUser.setRoles(roles);
User savedUser = save(newUser);
return savedUser;
}
return null;
}
@Transactional
public User save(User user) {
user.setPassword(bCryptPasswordEncoder.encode(user.getPassword()));
try {
user = userRepository.save(user);
} catch (org.springframework.dao.DataIntegrityViolationException ex) {
log.error(ex.getMessage());
return null;
}
return user;
}
@Override
public User updateUser(String oldUserName, UserDto userDto) {
Optional<User> optionalUser = userRepository.findByUsername(oldUserName);
optionalUser.orElseThrow(() -> new UsernameNotFoundException("User not found"));
// if (optionalUser != null) {
User user = optionalUser.get();
if (user != null) {
Set<Role> roleset = new HashSet<Role>();
if (userDto.getRole() != null && !userDto.getRole().isEmpty()) {
Role role = roleRepository.findByRole(userDto.getRole());
if (role != null) {
roleset.add(role);
}
}
user.setRoles(roleset);
user.setUsername(userDto.getUsername());
user = userRepository.save(user);
return user;
} else
return null;
}
当我尝试过
@ManyToMany(cascade = {CascadeType.MERGE,CascadeType.PERSIST}, fetch = FetchType.EAGER)
@JoinTable(name = "user_roles", joinColumns = @JoinColumn(name = "user_id"), inverseJoinColumns = @JoinColumn(name = "role_id"))
private Set<Role> roles;
我收到以下异常
Caused by: org.hibernate.PersistentObjectException: detached entity passed to persist: com.techjava.springbootsecuritymysql.model.Role
答案 0 :(得分:2)
错误detached entity passed to persist
是由于角色从EntityManager分离而引起的。这样做的原因是,它是在事务外部读取的,但是user_roles
中的关联已插入事务中。
要解决该问题,只需将@Transactional
添加到createUser
方法中。然后Role
在同一事务中被读取,并且不会被分离:
@Transactional
public User createUser(UserDto account) {
//...
}
另一件事是,您在@ManyToMany
上设置了级联。如果仅应使用User
自动保留和删除关联,则不需要这样做。无论使用什么cascase选项,它们都将始终自动创建和删除。
例如,当您想自动将Role
与User
插入时,就需要级联,而我假设您不希望从代码示例中插入。因此,只需删除级联:
@ManyToMany(fetch = FetchType.EAGER)
@JoinTable(name = "user_roles", joinColumns = @JoinColumn(name = "user_id"), inverseJoinColumns = @JoinColumn(name = "role_id"))
private Set<Role> roles;