Java Hibernate,双向更新

Java Hibernate,双向更新,java,hibernate,bidirectional-relation,Java,Hibernate,Bidirectional Relation,我试图用hibernate更新两个表(User和UserRole)中具有服务器角色的用户的记录。当我执行保存操作时,它工作正常,但是,当我尝试更新时,如果对象包含存储在数据库中的角色,它将失败。我没有找到一个好的答案,但我想它不能直接用“更新”方法来完成,应该在更新中手动实现双向,不是吗?。我跟着火车走 这是我的用户类: @Entity @Table(name = "users", schema = "cmsdb") public class User { private String use

我试图用hibernate更新两个表(User和UserRole)中具有服务器角色的用户的记录。当我执行保存操作时,它工作正常,但是,当我尝试更新时,如果对象包含存储在数据库中的角色,它将失败。我没有找到一个好的答案,但我想它不能直接用“更新”方法来完成,应该在更新中手动实现双向,不是吗?。我跟着火车走

这是我的用户类:

@Entity
@Table(name = "users", schema = "cmsdb")
public class User {

private String username;
private String password;
private boolean enabled;

private Set<UserRole> userRole = new HashSet<UserRole>(0);

public User() {
}

public User(String username, String password, boolean enabled) {
    this.username = username;
    this.password = password;
    this.enabled = enabled;
}

public User(String username, String password, 
    boolean enabled, Set<UserRole> userRole) {
    this.username = username;
    this.password = password;
    this.enabled = enabled;
    this.userRole = userRole;
}

@Id
@Column(name = "username", unique = true, nullable = false, length = 45)
public String getUsername() {
    return username;
}

public void setUsername(String username) {
    this.username = username;
}

@Column(name = "password", nullable = false, length = 60)
public String getPassword() {
    return password;
}

public void setPassword(String password) {
    this.password = password;
}

@Column(name = "enabled", nullable = false)
public boolean isEnabled() {
    return enabled;
}

public void setEnabled(boolean enabled) {
    this.enabled = enabled;
}

@OneToMany(fetch = FetchType.EAGER, mappedBy = "user")  //,cascade = {CascadeType.ALL}
@Cascade({CascadeType.SAVE_UPDATE,CascadeType.DELETE})
@OnDelete(action = OnDeleteAction.CASCADE)
public Set<UserRole> getUserRole() {
    return userRole;
}

public void setUserRole(Set<UserRole> userRole) {
    this.userRole = userRole;
}
}
以下是我的DAO方法:

// IT WORKS PROPERLY
@Override
@Transactional
public boolean createUser(User user) {
    String hashedPassword = passwordEncoder.encode(user.getPassword());
    user.setPassword(hashedPassword);

    Set<UserRole> roles = new HashSet<UserRole> ();
    for(UserRole role: user.getUserRole()) {
        roles.add(new UserRole(user,role.getRole()));   
    }

    user.setUserRole(roles);
    sessionFactory.getCurrentSession().save(user);
    return true;
}

// It doesn't work if it tries to update an User with an UserRole stored in the UserRole table in the database
@Override
@Transactional
public boolean updateUser(User user) {

// Get user by id
    User userpersis = (User) getSessionFactory().getCurrentSession().load(User.class, user.getUsername());

  // Primary key shouldn't be modified
  userpersis.setEnabled(user.isEnabled());
  userpersis.getUserRole().retainAll( user.getUserRole() );
  userpersis.getUserRole().addAll( user.getUserRole() );
  sessionFactory.getCurrentSession().update(userpersis);
  return true;
}

提前感谢。

用户
中,将
删除
添加到级联:

@Cascade(cascade={CascadeType.ALL}, orphanRemoval=true)
@OnDelete(action = OnDeleteAction.CASCADE)
public Set<UserRole> getUserRole() { ...
尽管事实上,您可能甚至不想删除所有用户角色,然后插入所有新数据。你也可以这样做

userpersis.getUserRole().retainAll( user.getUserRole() );
userpersis.getUserRole().addAll( user.getUserRole() );
但是,这需要在
UserRole
中实现
equals()
hashCode()


编辑:在您的情况下,
用户
的角色对象由于对所属对象的反向引用而不能与
用户的角色对象相同时,编辑当然不起作用。

哦,对不起,我没有注意到实际上您需要新对象。我正在编辑中的“新”信息:)感谢您的响应,实现了这一点,当我尝试更新具有一个已在持久化中的角色的用户时,我会出现以下错误,我猜是因为试图放置数据库中存在的对象
DataIntegrityViolationException:无法执行语句;SQL[n/a];约束[uni_用户名_角色];嵌套异常是org.hibernate.exception.ConstraintViolationException:无法执行语句
我想您不需要调用
会话.update(…)
。最后,我手动执行了retain和addAll方法,因为我在equals()和hashCode()方面遇到了问题。我发现这种方法在持久性方面存在一些问题,但这是本文的正确答案。谢谢
@Cascade(cascade={CascadeType.ALL}, orphanRemoval=true)
@OnDelete(action = OnDeleteAction.CASCADE)
public Set<UserRole> getUserRole() { ...
Set<UserRole> roles = new HashSet<UserRole> ();
// Guess for roles, should be needed to load them also from the db
for(UserRole role : user.getUserRole()) {
    roles.add(new UserRole(userpersis,role.getRole())); 
}

userpersis.setUserRole(roles);
userpersis.getUserRole().clear(); // Let Hibernate know that we're really removing all the references

for(UserRole role : user.getUserRole()) {
    userpersis.getUserRole().add(new UserRole(userpersis,role.getRole())); 
}
userpersis.getUserRole().retainAll( user.getUserRole() );
userpersis.getUserRole().addAll( user.getUserRole() );