休眠验证器导致多对多关系无法保存 [英] Hibernate validator causing many to many relationship to not save

查看:93
本文介绍了休眠验证器导致多对多关系无法保存的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在用户和角色之间有一个ManyToMany关系.我在用户"中的角色集上有一个自定义的休眠验证约束.

I have a ManyToMany relationship between User and Role. I have a custom hibernate validation constraint on my roles Set in User.

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

In a @PostConstruct I save the initial roles (ADMIN, USER) to the database using standard JpaRepository from spring-data-jpa. I then create an initial user using the admin role.

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

If I do not have my custom validation, the association is saved correctly and I see an entry in user_role join table. If I have the validation, the user is inserted into the user table, but without an entry into user_role table. 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.

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中运行此程序并将其安排在其他线程中,则它也可能会起作用,我需要检查一下.

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.

具有可重现的失败测试用例的项目:

Project with reproducible failing test case: https://github.com/tjhelmuth/SPR-22533/blob/master/src/test/java/spr22533/bug/BugExample.java

推荐答案

在验证过程中不能保证在验证期间访问EntityManager.

Accessing the EntityManager during validation is not guaranteed to work during validation.

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

Validation happens in "lifecycle callback methods". For these the following restriction applies (Java Persistence Specification 2.2; Section 3.5.2 Lifecycle Callback Methods):

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

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,由于它运行不同的事务,因此当然可能会遇到一组不同的更改.

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的正确方法休眠验证期间进行查询

这篇关于休眠验证器导致多对多关系无法保存的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆