休眠验证器导致多对多关系无法保存

时间:2019-03-06 21:29:18

标签: java spring hibernate spring-data-jpa hibernate-validator

我在用户和角色之间有一个ManyToMany关系。我对用户中的角色设置有一个自定义的休眠验证约束。

@PostConstruct中,我使用spring-data-jpa中的标准JpaRepository将初始角色(ADMIN,USER)保存到数据库中。然后,我使用管理员角色创建一个初始用户。

如果没有自定义验证,则关联将正确保存,并且在user_role连接表中看到一个条目。如果我已通过验证,则将用户插入到用户表中,但没有进入user_role表中。返回的实体在角色集中具有角色,但不会保存进入数据库。该代码总结如下。我不明白如何使用RoleRepo来获取所有角色会以何种方式破坏保存,但确实如此。

class User {
  @Id
  String username;

  @ValidOption
  @ManyToMany(cascade = {CascadeType.ALL //for example}, fetch=FetchType.EAGER)
  Set<Role> roles;
}

class Role {
  @Id
  String name;
}

class CustomValidator implements ConstraintValidator<ValidOption, Object> {
  RoleRepository roleRepo; //injected by spring... have spring factory

  @Override
  public boolean isValid(Object value, ConstraintValidatorContext context){
    roleRepo.findAll() //<-------------- THIS CALL BREAKS THE SAVE
    return true;
  }
}

@Component
class UserCreator {
  RoleRepository roleRepo;
  UserRepo userRepo;

  @PostConstruct
  void setup(){
    Role admin = roleRepo.saveAndFlush(new Role('ADMIN'));
    roleRepo.saveAndFlush(new Role('USER'));

    User user = new User('admin', Collections.singleton(admin));
    userRepo.save(user); //<------ DOES NOT INSERT ADMIN INTO USER_ROLE JOIN TABLE
  }
}

这完全符合我删除自定义验证器时的预期效果。如果我不在PostConstruct中运行此程序并将其安排在其他线程中,则它也可能会起作用,我需要检查一下。

具有可重现的失败测试用例的项目:https://github.com/tjhelmuth/SPR-22533/blob/master/src/test/java/spr22533/bug/BugExample.java

1 个答案:

答案 0 :(得分:2)

不能保证在验证期间访问C:\Program Files\MongoDB\Server\4.0\bin\mongod.exe

验证发生在“生命周期回调方法”中。 对于这些,适用以下限制(Java持久性规范2.2;第3.5.2节“生命周期回调方法”):

  

通常,可移植应用程序的生命周期方法不应调用EntityManager或查询操作,访问其他实体实例或在同一持久性上下文内修改关系。生命周期回调方法可能会修改在其上调用它的实体的非关系状态。

要使其正常工作,请使用单独的EntityManager,由于它运行不同的事务,因此当然可能会遇到一组不同的更改。

另请参阅:Correct way to do an EntityManager query during Hibernate Validation