7

I have entity user:

@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

Base object is: @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;
}

}

The proble is, when I try to UPDATE object, I am getting errors:

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'

For update entity I am using:

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

I am dont know why I am getting this error, how can I update my object? Thank you for your help.

EDIT: I update:

User u = em.find(persistedType, id); //get user by ID
u.getSetOfRequesSet().add(requestSet); //add one otem to set
userDap.merge(u); //save
  • That doesn't define HOW you attempt to update an object. Where do you get the object from? em.find() ? query? then is it detached? then you update some field(s) whilst detached? – Neil Stockton Aug 13 '16 at 08:19
  • Is there a transaction including both loading and updating of the user? If not I believe the entity gets detached so that Hibernate maybe does not know any more that it is the same as the one in database. Does it work with such a transaction or if you load the entity before merging in "save"? – mm759 Aug 13 '16 at 08:30
  • Are there multiple RequestSets with same ID? – mm759 Aug 13 '16 at 08:32
  • Yes. I want save `requestSet` with id `1` for more `users`. –  Aug 13 '16 at 08:33
  • If you just do a find then do an update you have no need to do a "merge", since the objects will be "managed" ... assuming all of that is in a single transaction. What is "requestSet" ? Is it already persistent, or a new object? – Neil Stockton Aug 13 '16 at 08:44
  • just use repository, it will do the work for you, no need to explicitly call entity manager – Andrii Plotnikov Aug 13 '16 at 09:03

1 Answers1

5

It looks like your update duplicates entries in the set (em.merge). To prevent the duplication you should merge set explicitly. Do as following.

  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);
    

Not necessary to cal to em.merge after the update, since save will be just done at the end of a transaction.

You can find the explanation here.

asch
  • 1,923
  • 10
  • 21