In my app, I have a many-to-many association between the User and Preference entities. Since the join table requires an additional column, I had to break it down into 2 one-to-many associations as such:
User entity :
@OneToMany(mappedBy = "user", fetch = FetchType.EAGER, cascade={CascadeType.PERSIST, CascadeType.MERGE}, orphanRemoval = true)
public Set<UserPreference> getPreferences()
{
return preferences;
}
Preference entity :
@OneToMany(mappedBy = "preference", fetch = FetchType.EAGER)
public Set<UserPreference> getUserPreferences()
{
return userPreferences;
}
UserPreference entity :
@ManyToOne
@JoinColumn(name = "user_id", nullable = false)
public User getUser()
{
return user;
}
public void setUser(User user)
{
this.user = user;
}
@ManyToOne
@JoinColumn(name = "preference_id", nullable = false)
public Preference getPreference()
{
return preference;
}
public void setPreference(Preference preference)
{
this.preference = preference;
}
@Column(nullable = false, length = 25)
public String getValue()
{
return value;
}
public void setValue(String value)
{
this.value = value;
}
To update one of the preferences, I loop through the user's set of preferences and update the value as such:
@RequestMapping(value = {"/edit-{id}-preference"}, method = RequestMethod.POST)
public String updateUserPreference(@ModelAttribute("userPreference") UserPreference preference, BindingResult result, ModelMap model)
{
User loggedInUser = (User)session.getAttribute("loggedInUser");
for (UserPreference pref : loggedInUser.getPreferences())
{
if (Objects.equals(pref.getId(), preference.getId()))
{
pref.setValue(preference.getValue());
}
}
userService.update(loggedInUser);
return "redirect:/users/preferences";
}
I have confirmed that the user variable I'm trying to update does indeed contain the new value after this code runs. Even weirder, the value does update on the webpage when the redirect happens but the database does NOT update! This is the code I'm using to do the update, this class is annotated with @Transactional and every other call to this method (to update the user's role for example) works perfectly:
@Override
public void update(User user)
{
User entity = dao.findById(user.getId());
if (entity != null)
{
entity.setUserId(user.getUserId());
entity.setPassword(user.getPassword());
entity.setFirstName(user.getFirstName());
entity.setLastName(user.getLastName());
entity.setRole(user.getRole());
entity.setPreferences(user.getPreferences());
}
}
This acts like hibernate's session "cache" has the updated value but does not actually persist it. I am using this very same update method style for about 30 other entities and everything works fine. This is my only many-to-many association that I had to break down into 2 one-to-many associations so I have nothing to compare to.
Am I doing something wrong? When I create a user with a new HashSet and persist it, the value is written correctly in the "join table".
*****EDIT*****
For comparison, this is the code I use to create a new user with default preferences. The preferences exist already but the join table is completely empty and this code correctly persists the entities:
User user = new User();
user.setUserId("admin");
user.setPassword(crypter.encrypt("admin"));
user.setFirstName("admin");
user.setLastName("admin");
user.setRole(roleService.findByName("Admin"));
Set<UserPreference> userPreferences = new HashSet<>();
Preference preference = preferenceService.findByName("anchorPage");
UserPreference userPreference = new UserPreference();
userPreference.setUser(user);
userPreference.setPreference(preference);
userPreference.setValue("System Statistics");
userPreferences.add(userPreference);
preference = preferenceService.findByName("showOnlyActivePatients");
userPreference = new UserPreference();
userPreference.setUser(user);
userPreference.setPreference(preference);
userPreference.setValue("true");
userPreferences.add(userPreference);
user.setPreferences(userPreferences);
userService.save(user);
Thanks
Instead of
entity.setPreferences(user.getPreferences());
Do something like:
for( UserPreference uf : user.getPreferences() ) {
entity.getPreferences().add( uf );
}
The main difference here is that you aren't changing the list reference, which is managed by Hibernate, and is only adding elements to it.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With