Spring数据jpa分离实体

我开始使用Spring Data JPA处理Spring Boot应用程序,以在用户和角色之间建立ManyToMany关系。

此关系在User类中定义如下:

@ManyToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL) @JoinTable(name="user_role", joinColumns = {@JoinColumn(name="user_id")}, inverseJoinColumns = {@JoinColumn(name="role_id")}) private Set roles; 

我创建角色使用:

 @Transactional private void generateSeedRoles() { UserRole adminRole = new UserRole(RoleEnum.ADMIN.toString()); userRoleRepository.save(adminRole); UserRole userRole = new UserRole(RoleEnum.USER.toString()); userRoleRepository.save(userRole); } 

之后为用户分配角色失败:

 @Transactional private void generateSeedUsers() { UserRole adminRole = userRoleRepository.findUserRoleByRoleName("ADMIN"); User user = User.createUser("user1", "user1@user.com", "pass"); user.setRoles(new HashSet(Arrays.asList(adminRole))); userRepository.save(user); } 

抛出以下exception(为便于阅读而格式化):

 org.springframework.dao.InvalidDataAccessApiUsageException: detached entity passed to persist: co.feeb.models.UserRole; nested exception is org.hibernate.PersistentObjectException: detached entity passed to persist: co.feeb.models.UserRole 

但是,如果在创建关系之前保存用户,则可以正常工作:

 @Transactional private void generateSeedUsers() { UserRole adminRole = userRoleRepository.findUserRoleByRoleName("ADMIN"); User user = User.createUser("user1", "user1@user.com", "pass"); //Save user userRepository.save(user); //Build relationship and update user user.setRoles(new HashSet(Arrays.asList(adminRole))); userRepository.save(user); } 

必须两次保存/更新用户对我来说似乎有些不合理。 有没有办法将收到的角色分配给新用户而不先保存用户?

当您保存实体时,Spring会在内部检查实体是否是新的(我忘记确切的机制),并发出持久性(如果是新的)或合并(如果存在的话)。

由于您已经使用Cascade.ALL定义了User与UserRole的关系,因此来自User的任何持久/合并也将级联到UserRole。

鉴于Spring如何实现保存以及上面级联的行为,以下是一些需要考虑的方案:

  • 如果User和UserRole都是新的 – 你在保存用户时会得到一个持久动作,并且一个级联持久存在UserRole,由于UserRole是新的,因此工作正常。
  • 如果用户是新用户但UserRole已存在 – 再次保存用户时会得到一个持久动作,并且级联持续存在到UserRole,这会导致错误,因为UserRole已经存在!

如果您可以保证添加到用户关系的任何UserRole始终存在,您只需从级联选项中删除Cascade.Persist即可。 否则,我相信在上述两种情况下保存用户时,您必须使用合并 – 通过自定义存储库和entityManager。

关于你使用Cascade.ALL,在这种情况下可能没有意义,因为你有一个@ManyToMany关系,从用户到UserRole级联ALL可能会产生一些不良影响(例如Cascade.Remove会每次删除UserRole用户被删除)。