2017-08-29 162 views
1

我有一個具有以下獨特的約束建立一個實體類:Hibernate的複雜的唯一約束

@Table(name = "foo", uniqueConstraints = { 
@UniqueConstraint(columnNames = {"service", "system", "priority", "is_default"})}) 

凡服務和系統的其他實體類的外鍵,優先級是一個整數控股條目中的條目的優先級具有相同的服務和系統對象,is_default是一個表示默認配置條目的布爾值。

這個獨特的約束幾乎做我想做的事情,但我需要的是一個設置,其中,如果is_default是FALSE那麼可以有多個條目具有相同的服務和系統鍵只是具有不同的整數優先級,而如果is_default是TRUE那麼對於給定的服務和系統密鑰只能有1個條目,這意味着給定的服務和系統只能有1個默認條目。我怎樣才能達到這樣的限制?

+0

恐怕你必須寫自己的驗證註釋。 –

+0

感謝您的提示,我會試着理解這一個:https://docs.jboss.org/hibernate/validator/5.0/reference/en-US/html/validator-customconstraints.html#validator-customconstraints –

回答

1

關鍵是創建您自己的驗證註釋,能夠根據特定條件驗證行數據是否唯一。

讓服務iterface延長UniqueValidated和落實執行驗證

public interface UniqueValidated { 
    boolean isUnique(Object value, String fieldName) throws UnsupportedOperationException; 
} 

public interface FooService extends UniqueValidated { 
    // add, delete... 
} 

public class FooServiceImpl implements FooService { 

    // add, delete... 

    @Override 
    public boolean isUnique(Object value, String fieldName) 
     throws UnsupportedOperationException { 

     // the logic of validation itself, feel free to use DAO implementations 
    } 
} 

創建你把在映射屬性註釋的方法。

@Target({ ElementType.METHOD, ElementType.FIELD, ElementType.ANNOTATION_TYPE 
}) 
@Retention(RetentionPolicy.RUNTIME) 
@Constraint(validatedBy = UniqueValidator.class) 
@Documented 
public @interface Unique { 
    String message() default "{validation.unique}"; 
    Class<?>[] groups() default {}; 
    Class<? extends Payload>[] payload() default {}; 
    Class<? extends UniqueValidated> service(); 
    String serviceQualifier() default ""; 
    String fieldName(); 
} 

最後創建帶註釋的類處理。

public class UniqueValidator implements ConstraintValidator<Unique, Object> { 

    @Autowired 
    private ApplicationContext applicationContext; 
    private UniqueValidated service; 
    private String fieldName; 

    @Override 
    public void initialize(Unique unique) { 
     Class<? extends UniqueValidated> clazz = unique.service(); 
     this.fieldName = unique.fieldName(); 
     this.service = this.applicationContext.getBean(clazz); 
    } 

    @Override 
    public boolean isValid(Object o, ConstraintValidatorContext constraintValidatorContext) { 
     if (this.service == null || this.service.isUnique(o, this.fieldName)) { 
      constraintValidatorContext.disableDefaultConstraintViolation(); 
      return true; 
     } 
     return false; 
    } 
} 

我從JBoss Docs的在線教程中獲得啓發。這是相當複雜的結構,但它很好地導致了結果。最大的優勢無疑是您可以通過任何實施UniqueValidated的服務對自定義進行獨特驗證。無論如何,你需要上面這些片段爲你的項目定製。

映射很簡單:

@Unique(service = FooService.class, fieldName = "theNameOfThisField" 
@Column(name = "...") 
private String theNameOfThisField; 
+0

我對此有點困惑,你是否在暗示我的Foo實體類中的服務類型字段(也是一個實體類)?我怎麼能爲我的用例編寫它的isUnique方法,當我需要System對象時,也可以查詢數據庫,並對返回的條目進行驗證。我認爲我需要某種自定義的Foo類本身的約束。 –

+0

您可以將約束放置到DAO層,或者放到與數據庫接觸的任何其他類中。註釋本身不做任何事情,必須有一個層負責主體對實體的CRUD操作,並且在層內執行驗證邏輯是有意義的。 –