0

I got the UserDetails entity form database and passed it as model attribute (MVC). Later, I tried to update the updated UserDetails entity in database. Now I am getting this error. My doubts are

  1. What is the use case of CascadeType.MERGE
  2. How Hibernate handles entities
  3. How can I update existing entity which is associated with another entity.

Multiple representations of the same entity [com.rajath.instagram.entity.UserDetails#1] are being merged. Managed: [com.rajath.instagram.entity.UserDetails@637bce04]; Detached: [com.rajath.instagram.entity.UserDetails@2b6247fa]; nested exception is java.lang.IllegalStateException: Multiple representations of the same entity [com.rajath.instagram.entity.UserDetails#1] are being merged. Managed: [com.rajath.instagram.entity.UserDetails@637bce04]; Detached: [com.rajath.instagram.entity.UserDetails@2b6247fa]] with root cause java.lang.IllegalStateException: Multiple representations of the same entity [com.rajath.instagram.entity.UserDetails#1] are being merged. Managed: [com.rajath.instagram.entity.UserDetails@637bce04]; Detached: [com.rajath.instagram.entity.UserDetails@2b6247fa]

Controller Layer:

@PostMapping("/addUserDetails")
public String adduserDetails(@ModelAttribute("user") UserDetails userDetails) {
   User user = (User) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
   regisrationService.updateUserDetails(user.getUsername(), userDetails);
   return "redirect:/register/addProfilePhoto";
}

Service Layer:

@Override
@Transactional
public void updateUserDetails(String username, UserDetails userDetails) {
    
    Optional<InstagramUser> opt = instagramUserJpaDao.findById(username);
    InstagramUser user = opt.get();

    userDetails.setUser(user);
    userDetailsJpaDao.saveAndFlush(userDetails);
}

Dao Layer:

@Override
public void updateUserDetails(String username, UserDetails userDetails) {

    Session session = manager.unwrap(Session.class);
    InstagramUser user = session.get(InstagramUser.class, username);
    userDetails.setUser(user);
        
    user.setUserDetails(userDetails);
    session.saveOrUpdate(userDetails);
}

My entities are:

  1. Instagramuser
// From user details table
@OneToOne(mappedBy="user", fetch=FetchType.LAZY,            cascade=CascadeType.ALL)
private UserDetails userDetails;
  1. UserDetails
    // From user table, @OneToOne matching because, only one user details entry for a user
@OneToOne(fetch=FetchType.EAGER,
          cascade= {CascadeType.DETACH, CascadeType.MERGE, CascadeType.PERSIST, CascadeType.REFRESH})
@JoinColumn(name="username")
private InstagramUser user;
SternK
  • 7,358
  • 5
  • 22
  • 32

1 Answers1

0

The problem with your code is likely that InstagramUser.userDetails is not really lazy, so the current UserDetails also gets loaded into the context, hence the error. Try adding optional = false to the mapping to see if the problem goes away. (See the last paragraph of my answer for why this is not the correct solution)

Alternatively, you can try to reorder your code in the following way:

UserDetails merged = userDetailsJpaDao.save(userDetails); // I am assuming userDetails.user is null at this point
instagramUserJpaDao.findById(username)
    .ifPresent(instagramUser -> merged.setUser(instagramUser));

Also note that, since in your original code InstagramUser.user is the inverse side of the association, the line user.setUserDetails(userDetails); really doesn't do anything. You need to populate UserDetails.user instead to establish an association between the two entities.

crizzis
  • 7,901
  • 2
  • 22
  • 36