在Spring JPA中插入多对多单向关系

时间:2018-08-12 22:38:15

标签: java mysql spring hibernate jpa

我有两个表,用户和角色。角色类似于“ 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

1 个答案:

答案 0 :(得分:2)

错误detached entity passed to persist是由于角色从EntityManager分离而引起的。这样做的原因是,它是在事务外部读取的,但是user_roles中的关联已插入事务中。

要解决该问题,只需将@Transactional添加到createUser方法中。然后Role在同一事务中被读取,并且不会被分离:

@Transactional
public User createUser(UserDto account) {
//...
}

另一件事是,您在@ManyToMany上设置了级联。如果仅应使用User自动保留和删除关联,则不需要这样做。无论使用什么cascase选项,它们都将始终自动创建和删除。 例如,当您想自动将RoleUser插入时,就需要级联,而我假设您不希望从代码示例中插入。因此,只需删除级联:

@ManyToMany(fetch = FetchType.EAGER)
@JoinTable(name = "user_roles", joinColumns = @JoinColumn(name = "user_id"), inverseJoinColumns = @JoinColumn(name = "role_id"))
private Set<Role> roles;