2017-08-29 15 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

チップをありがとう、私はこの1つを理解しようとするつもりです: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操作を担当するレイヤが必要であり、レイヤ内で検証ロジックを実行することは理にかなっています。 –

関連する問題