【问题标题】:Skip unique constraint bean validation when editing existing entity编辑现有实体时跳过唯一约束 bean 验证
【发布时间】:2016-08-15 10:42:23
【问题描述】:

我有一个独特的字段验证问题。这可能适用于任何对象上的任何唯一字段,但在我现在的情况下,我有一个用户,我希望用户名在数据库中是唯一的。

来自我的用户的 sn-p:

@Entity
public class User {

    @NotNull
    @Column(unique = true)
    @UniqueUsername
    private String username;
}

UniqueUsername 是自定义约束注解如下:

@Constraint(validatedBy =  {UniqueUsernameValidator.class})
public @interface UniqueUsername {

    String message() default "User already exists with this username";

    Class<?>[] groups() default {};

    Class<? extends Payload>[] payload() default {};
}

那么 UniqueUsernameValidator 是一个自定义约束验证器,它只检查数据库中具有给定用户名的现有用户:

@ApplicationScoped
public class UniqueUsernameValidator implements ConstraintValidator<UniqueUsername, String> {

    @Inject
    private UserRepository userRepo;

    @Override
    public boolean isValid(String value, ConstraintValidatorContext context) {
        boolean valid = false;
        try {
            userRepo.findByUsername(value);
        } catch (NoResultException e) {
            // No result means username not already used
            valid = false
        }
        return valid;
    }
}

现在对于新用户,验证效果很好。我遇到的问题是当我编辑一个已经存在的用户时。当用户更新时,验证会找到我当前正在编辑的用户,返回 false 并拒绝编辑。

理想情况下,我的验证器可能有权访问/了解正在验证的用户对象(而不仅仅是字段值),以便我可以检查我在数据库中找到的重复对象是否与正在编辑的对象相同。但我在验证器中找不到这样做的方法。

还有其他人遇到过这个问题并提出了可接受的解决方案吗?

【问题讨论】:

    标签: jakarta-ee bean-validation unique-constraint


    【解决方案1】:

    如何使用用户名和生成的主键 (ID) 的组合。使用 id 进行引用会更快,并且您将获得更多信息,如果您正在更新或创建新实体,这些信息可以解决。

    您的验证将需要移至实体级别,然后您可以检查实体是否具有空 id(创建新)或具有某些 id(更新现有)。

    创建新的时检查是否不存在其他同名实体。 更新时进行相同的检查,但如果您找到具有相同名称的实体,请确保它不是同一个实体 - 使用 id。

    正如您所写,这种情况不仅与用户有关,而且与一般实体有关,这种方法也可以解决具有多个唯一字段的情况。

    【讨论】:

      【解决方案2】:

      我遇到了同样的问题,我以这种方式跳过了更新操作的验证器:

      @Override
      public boolean isValid(String email, ConstraintValidatorContext constraintValidatorContext) {
      
          StackTraceElement[] elements = Thread.currentThread().getStackTrace();
      
          for (int i = 0; i < elements.length; i++) {
              StackTraceElement element = elements[i];
              if(element.getMethodName().equals("preUpdate")){
                  return true;
              }
          }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多