2016-08-15 61 views
1

我有一個獨特的字段valiation問題。這可能適用於任何對象上的任何唯一字段,但就我而言,現在我有一個用戶,並且我希望用戶名在數據庫中是唯一的。編輯現有實體時跳過唯一的約束bean驗證

甲從我的用戶片段:

@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是一個自定義約束驗證器,簡單地檢查DB,用於與現有的用戶給定用戶名:

@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; 
    } 
} 

現在對於一個ne w用戶,驗證工作很好。我遇到的問題是編輯已存在的用戶。當用戶更新時,驗證會查找我當前正在編輯的用戶,並返回false並拒絕編輯。

理想情況下,我的驗證器可能會訪問/知道正在驗證的用戶對象(而不僅僅是字段值),以便我可以檢查在數據庫中找到的重複對象是否與正在編輯的相同。但我無法在驗證器中找到這樣做的方法。

其他人遇到這個問題,並拿出一個可接受的解決方案?

回答

0

如何使用用戶名和生成的主鍵(ID)的組合。如果您正在更新或創建新實體,使用id作爲引用的速度會更快,並且您將獲得可以解決的其他信息。

您的驗證需要移到實體級別,然後您可以檢查實體是否具有空id(創建新的)或具有某個id(更新現有)。

當創建新的時候,檢查是否不存在其他具有相同名稱的實體。 更新時執行相同的檢查,但如果您找到具有相同名稱的實體,請確保它不是相同的實體 - 使用id。

正如你所寫,這種情況不僅僅是關於用戶,而是關於一般實體,這種方法也可以解決多個獨特領域的情況。

-1

我面臨同樣的問題,我跳過了驗證以這種方式更新操作:

@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; 
     } 
    }