Hibernate 验证器导致多对多关系无法保存
Hibernate validator causing many to many relationship to not save
我在用户和角色之间存在多对多关系。我对我在用户中设置的角色设置了自定义休眠验证约束。
在 @PostConstruct
中,我使用来自 spring-data-jpa 的标准 JpaRepository 将初始角色(ADMIN、USER)保存到数据库中。然后我使用管理员角色创建一个初始用户。
如果我没有自定义验证,关联会正确保存,我会在 user_role
join table 中看到一个条目。如果我进行了验证,则将用户插入到用户 table、 但没有进入 user_role
table。 返回的实体具有角色集中的角色,但未保存到数据库中。代码总结如下。我无法理解如何使用 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
}
}
如果我删除自定义验证器,这 100% 完全符合我的预期。如果我不在 PostConstruct 中 运行 并将其安排在不同的线程中,它也可能有效,我需要检查一下。
具有可重现的失败测试用例的项目:https://github.com/tjhelmuth/SPR-22533/blob/master/src/test/java/spr22533/bug/BugExample.java
不能保证在验证期间访问 EntityManager
。
验证发生在 "lifecycle callback methods"。
对于这些应用以下限制(Java 持久性规范 2.2;第 3.5.2 节生命周期回调方法):
In general, the lifecycle method of a portable application should not invoke EntityManager or query operations, access other entity instances, or modify relationships within the same persistence context. A lifecycle callback method may modify the non-relationship state of the entity on which it is invoked.
要使其正常工作,请使用单独的 EntityManager
,这当然可能会因为运行不同的事务而看到不同的更改集。
另请参阅:Correct way to do an EntityManager query during Hibernate Validation
我在用户和角色之间存在多对多关系。我对我在用户中设置的角色设置了自定义休眠验证约束。
在 @PostConstruct
中,我使用来自 spring-data-jpa 的标准 JpaRepository 将初始角色(ADMIN、USER)保存到数据库中。然后我使用管理员角色创建一个初始用户。
如果我没有自定义验证,关联会正确保存,我会在 user_role
join table 中看到一个条目。如果我进行了验证,则将用户插入到用户 table、 但没有进入 user_role
table。 返回的实体具有角色集中的角色,但未保存到数据库中。代码总结如下。我无法理解如何使用 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
}
}
如果我删除自定义验证器,这 100% 完全符合我的预期。如果我不在 PostConstruct 中 运行 并将其安排在不同的线程中,它也可能有效,我需要检查一下。
具有可重现的失败测试用例的项目:https://github.com/tjhelmuth/SPR-22533/blob/master/src/test/java/spr22533/bug/BugExample.java
不能保证在验证期间访问 EntityManager
。
验证发生在 "lifecycle callback methods"。 对于这些应用以下限制(Java 持久性规范 2.2;第 3.5.2 节生命周期回调方法):
In general, the lifecycle method of a portable application should not invoke EntityManager or query operations, access other entity instances, or modify relationships within the same persistence context. A lifecycle callback method may modify the non-relationship state of the entity on which it is invoked.
要使其正常工作,请使用单独的 EntityManager
,这当然可能会因为运行不同的事务而看到不同的更改集。
另请参阅:Correct way to do an EntityManager query during Hibernate Validation