2017-08-29 156 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操作,并且在层内执行验证逻辑是有意义的。 –