【问题标题】:Insertion in Many to Many unidirectional relationship in Spring JPA在 Spring JPA 中插入多对多单向关系
【发布时间】:2018-08-12 22:38:15
【问题描述】:

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

}

假设我手动向角色插入了 3 条记录

INSERT INTO `role` VALUES (1,'ADMIN');
INSERT INTO `role` VALUES (2,'MANAGER');
INSERT INTO `role` VALUES (3,'USER');

现在我想插入到 User 表中,这样只有 user 和 user_roles(join table) 被插入:

例如: 如果我想插入一个 userId=1 和 role={ADMIN,MANAGER} 的用户,应该插入 user 表中的一个条目和 user_roles 表中的 2 个条目,如 (1,1)(1,2)。不应向 Roles 表插入任何内容。我如何做到这一点?

我尝试将 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

【问题讨论】:

  • 您是否尝试过完全删除cascade?我不完全确定它在这里做了什么。我认为不需要。并且:究竟什么不起作用?是否插入了用户但未插入 user_roles 中的条目?你有错误吗?插入用户的代码是什么样子的?
  • @x4rf41 更新了问题
  • 错误状态,您传递的角色已分离(这意味着它不再被休眠实体管理器跟踪)。我认为问题在于,您在事务外部读取角色,然后在事务内部插入关联。可以请尝试两件事:1。将@Transactional 添加到createUser 方法。 2.从@ManyToMany中删除casade(或将其设置为cascade = {}
  • 嘿@x4rf41 它与您提到的上述步骤一起工作......谢谢......
  • 不错。 @stallion我用更多的解释来回答它。如果你能接受就好了

标签: java mysql spring hibernate jpa


【解决方案1】:

错误detached entity passed to persist是由于角色与entityManager分离造成的。原因是它是在事务外部读取的,但user_roles 中的关联插入到事务中。

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

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

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

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-10-28
    • 2020-07-22
    • 2022-01-26
    • 1970-01-01
    • 2023-01-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多