CascadeType.MERGE实际做什么?

时间:2020-10-27 13:03:21

标签: spring-boot hibernate jpa

我获得了UserDetails实体表单数据库,并将其作为模型属性(MVC)传递了。后来,我尝试更新数据库中更新的UserDetails实体。 现在我收到此错误。 我的疑问是

  1. CascadeType.MERGE的用例是什么
  2. Hibernate如何处理实体
  3. 如何更新与另一个实体关联的现有实体。

同一实体[com.rajath.instagram.entity.UserDetails#1]的多个表示形式正在被合并。托管:[com.rajath.instagram.entity.UserDetails@637bce04];分离:[com.rajath.instagram.entity.UserDetails@2b6247fa];嵌套的异常是java.lang.IllegalStateException:同一实体[com.rajath.instagram.entity.UserDetails#1]的多个表示形式正在被合并。托管:[com.rajath.instagram.entity.UserDetails@637bce04];分离:[com.rajath.instagram.entity.UserDetails@2b6247fa]有根本原因 java.lang.IllegalStateException:同一实体[com.rajath.instagram.entity.UserDetails#1]的多个表示形式正在被合并。托管:[com.rajath.instagram.entity.UserDetails@637bce04];分离:[com.rajath.instagram.entity.UserDetails@2b6247fa]

控制器层:

@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";
}

服务层:

@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层:

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

我的实体是:

  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;

1 个答案:

答案 0 :(得分:0)

您的代码存在问题,很可能InstagramUser.userDetailsnot really lazy,因此当前的UserDetails也被加载到上下文中,从而导致错误。 尝试将optional = false添加到映射中以查看问题是否消失。 (有关为什么这不是正确的解决方案,请参见答案的最后一段)

或者,您可以尝试通过以下方式对代码重新排序:

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

还要注意,由于在原始代码InstagramUser.user中是关联的反面,因此user.setUserDetails(userDetails);行实际上什么也没做。您需要填充UserDetails.user才能在两个实体之间建立关联。

相关问题