简体   繁体   English

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

[英]Hibernate validator causing many to many relationship to not save

I have a ManyToMany relationship between User and Role. 我在用户和角色之间有ManyToMany关系。 I have a custom hibernate validation constraint on my roles Set in User. 我对用户中的角色设置有一个自定义的休眠验证约束。

In a @PostConstruct I save the initial roles (ADMIN, USER) to the database using standard JpaRepository from spring-data-jpa. @PostConstruct我使用spring-data-jpa中的标准JpaRepository将初始角色(ADMIN,USER)保存到数据库中。 I then create an initial user using the admin role. 然后,我使用admin角色创建一个初始用户。

If I do not have my custom validation, the association is saved correctly and I see an entry in user_role join table. 如果没有自定义验证,则关联将正确保存,并且在user_role连接表中看到一个条目。 If I have the validation, the user is inserted into the user table, but without an entry into user_role table. 如果我有验证,则将用户插入到用户表中, 但没有到user_role表中的条目。 The returned entity has the role in the roles set, but it is not saved into the DB. 返回的实体在角色集中具有该角色,但不会保存到数据库中。 The code is summarized below. 该代码总结如下。 I cannot understand how using the RoleRepo to fetch all of the roles could in any way break the save, but it does. 我不明白如何使用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
  }
}

This works 100% exactly the way I would expect if I remove the custom validator. 这完全符合我删除自定义验证程序时的预期效果。 It may also work if I don't run this in PostConstruct and schedule it in a different thread, I need to check that. 如果我没有在PostConstruct中运行它并将它安排在另一个线程中,那么它也可能会起作用,我需要检查一下。

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

Accessing the EntityManager during validation is not guaranteed to work during validation. 验证期间不能保证在验证期间访问EntityManager

Validation happens in "lifecycle callback methods". 验证发生在“生命周期回调方法”中。 For these the following restriction applies (Java Persistence Specification 2.2; Section 3.5.2 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. 通常,便携式应用程序的生命周期方法不应调用EntityManager或查询操作,访问其他实体实例或修改同一持久性上下文内的关系。 A lifecycle callback method may modify the non-relationship state of the entity on which it is invoked. 生命周期回调方法可以修改在其上调用它的实体的非关系状态。

To make it work, use a separate EntityManager , which of course might suffer from seeing a different set of changes since it runs a different transaction. 要使其工作,请使用单独的EntityManager ,因为它运行不同的事务,因此当然可能会遇到一组不同的更改。

See also: Correct way to do an EntityManager query during Hibernate Validation 另请参阅: 在休眠验证期间执行EntityManager查询的正确方法

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM