Semyon Danilov
Semyon Danilov

Reputation: 1773

Hibernate Constraint Violation Exception

I'm using Spring with Hibernate and I'm getting this exception. Here is what I'm trying to get: I have User and UserSettings classes, they're bounded with OneToMany and ManyToOne annotations like this:

public class UserImpl implements User, Serializable {

...some fields 

    @OneToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL, mappedBy = "user", orphanRemoval = true)
    private Set<UserSettingsImpl> settings;

}

public class UserSettingsImpl implements UserSettings, Serializable {

...some fields

    @ManyToOne(cascade = CascadeType.ALL)
    private UserImpl user;

}

Now, I want to add settings for user, that's how I'm doing it:

public long addSettings(final UserSettings settings) {
    userSettingsDAO.persist((UserSettingsImpl) settings);
    UserSettingsImpl settingsImpl = (UserSettingsImpl) settings;
    User user = settings.getUser();
    Set<UserSettingsImpl> settingsSet = (Set<UserSettingsImpl>) user.getSettingsSet();
    settingsSet.add(settingsImpl);
    userManager.updateUser(user); //it's just entityManager.merge(user);
    return ((UserSettingsImpl) settings).getId();
}

And here comes the problem: User from UserSettings holds set with old settings and the new one (the settings, that I've just created and want to add), but old settings holds sets with user, that don't have new settings in it. That's why I'm getting the exception, I suppose, but I don't know how to fix it. (I think I'm working with Hibernate in the wrong way)

Upvotes: 1

Views: 369

Answers (2)

Hrishikesh
Hrishikesh

Reputation: 2053

You will get old Usersettings in the user object with the current setup. It is because, the way the merge method works. The way it works is it will create a copy of the object and then persist and refresh the object and return it back. So, in essense, the user object which you do pass in to the userManager will not be updated, but you have to get the returning value for the updated user

Upvotes: 1

Emilien Brigand
Emilien Brigand

Reputation: 10991

I would try something like below, the userImpl is referenced by the relationship from UserSettingsImpl, if you persist UserSettingsImpl, the operation is applied to the UserImpl because of the cascade, and if UserImpl is new it will be persisted otherwise nothing happens.

public long saveSettings(final UserSettings settings) {
    userSettingsDAO.persist((UserSettingsImpl) settings);
    return ((UserSettingsImpl) settings).getId();
}

and manage the bidirectional relationship in the class UserImpl:

 @OneToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL, mappedBy = "user", orphanRemoval = true)
 private Set<UserSettingsImpl> settings = new HashSet<UserSettingsImpl>();

 public void addUserSettings(UserSettings userSettings) {
    this.settings.add(userSettings);
    userSettings.setUserImpl(this);
 }

Upvotes: 0

Related Questions