如何使用Hibernate更新实体

7

我有一个实体用户:

@Entity
@Table(name = "entity_user")
@AttributeOverride(name = "id", column = @Column(name = "user_id"))
public class User extends BaseObject implements Serializable {

    /**
     * Login, unique
     */
    private String email;

    private String username;

    /**
     * Secret for signing-in
     */
    private String password;

    /**
     * Type of user
     */
    private UserType userType;

    @OneToMany(fetch = FetchType.EAGER, cascade = {CascadeType.ALL})
    @JoinTable(name = "view_user_to_requestSet", joinColumns = {
        @JoinColumn(name = "user_id")}, inverseJoinColumns = {
        @JoinColumn(name = "requestSet_id")})
    private Set<RequestSet> setOfRequesSet = new HashSet<>();

    @OneToMany(fetch = FetchType.EAGER, cascade = {CascadeType.ALL})
    @JoinTable(name = "view_user_to_requestSetCreator", joinColumns = {
        @JoinColumn(name = "user_id")}, inverseJoinColumns = {
        @JoinColumn(name = "requestSet_id")})
    private Set<RequestSet> setOfRequesSetCreator = new HashSet<>();

    @OneToMany(fetch = FetchType.EAGER, cascade = {CascadeType.ALL})
    @JoinTable(name = "view_user_to_userTask", joinColumns = {
        @JoinColumn(name = "user_id")}, inverseJoinColumns = {
        @JoinColumn(name = "userTask_id")})
    private Set<UserTask> setOfUserTask = new HashSet<>();

    public User() {
    }

    .
    .
..... GET AND SET

基础对象是: @MappedSuperclass public class BaseObject {
@Id
@GeneratedValue
@Column(name = "entity_id")
private Long id;

/**
 *
 * @return true if the entity hasn't been persisted yet
 */
@Transient
public boolean isNew() {
    return id == null;
}

public Long getId() {
    return id;
}

public void setId(Long id) {
    this.id = id;
}

问题在于,当我尝试更新对象时,会出现错误:

Exception in thread "Thread-15" org.springframework.dao.DataIntegrityViolationException: could not execute statement; SQL [n/a]; constraint [UK_5fa729oayn43ynq4v2y4d9qcn]; nested exception is org.hibernate.exception.ConstraintViolationException: could not execute statement

Caused by: org.hibernate.exception.ConstraintViolationException: could not execute statement

Caused by: com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolationException: Duplicate entry '5' for key 'UK_5fa729oayn43ynq4v2y4d9qcn'

我使用以下方法来更新实体:

@Transactional
public void save(User value){
   em.merge(value);
}

我不知道为什么会出现这个错误,我该如何更新我的对象?谢谢你的帮助。

编辑: 我已经更新:

User u = em.find(persistedType, id); //get user by ID
u.getSetOfRequesSet().add(requestSet); //add one otem to set
userDap.merge(u); //save

这并没有定义你如何尝试更新一个对象。你从哪里获取对象?em.find()?查询?然后它是分离的吗?然后你在分离状态下更新一些字段? - Neil Stockton
是否存在同时加载和更新用户的事务?如果没有,我认为实体将被分离,因此Hibernate可能不再知道它与数据库中的实体相同。在这样的事务中是否有效,或者您是否需要在“保存”之前加载实体并进行合并? - mm759
有多个具有相同ID的请求集吗? - mm759
是的。我想为更多的“用户”保存具有ID“1”的“requestSet”。 - user6701559
如果您只是进行查找,然后进行更新,那么您就不需要执行“合并”,因为对象将被“管理”...假设所有这些都在单个事务中。什么是“requestSet”?它已经持久化了吗,还是一个新对象? - Neil Stockton
只需使用存储库,它会为您完成工作,无需显式调用实体管理器。 - Andrii Plotnikov
1个回答

5

看起来你的更新在集合中复制了条目(em.merge)。 为了防止重复,你应该显式地合并集合。请按照以下步骤操作。

  1. Add method merge to User:

    protected User merge(User other) {
        // Just assign all data members(2 examples here)
        setEmail(other.getEmail());
        ....
        setSetOfRequesSet(other.getSetOfRequesSet());
        ...            
    }
    
  2. Prepare an updated object instance:

    User updated = em.find(persistedType, id); //get user by ID
    updated.getSetOfRequesSet().add(requestSet); //add one item to set
    
  3. Update the existing db entity:

    User existing = em.find(persistedType, id);
    existing.merge(updated);
    

在更新后不需要调用em.merge,因为保存将仅在事务结束时完成。

您可以在此处找到解释。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接