web-dev-qa-db-fra.com

Contrainte unique avec JPA et la validation du bean

J'aimerais avoir un @Unique contrainte avec Bean Validation, mais qui n'est pas fournie par la norme. Si j'utilisais le JPA @UniqueConstraint Je n'aurais pas de mécanisme de validation et de rapport d'erreurs unique.

Existe-t-il un moyen de définir @Unique en tant que contrainte de validation de bean et la combiner avec JPA, de telle sorte que JPA crée une colonne avec une contrainte unique et vérifie si une valeur est unique ou non?

38
deamon

À moins d'acquérir un verrou sur une table entière , il n'est fondamentalement pas possible de vérifier l'unicité à l'aide d'une requête SQL (toute transaction simultanée pourrait modifier les données après un contrôle manuel mais avant la validation de la transaction en cours). En d'autres termes, il n'est pas possible d'implémenter une vérification unique valide au niveau Java et donc de fournir une implémentation de validation. Le seul moyen fiable de vérifier l'unicité est de valider la transaction.

La spécification BV le résume comme ceci:

Annexe D. Java Intégration Persistence 2.

Question: devrions-nous ajouter @Unique qui serait mappé à @Column (unique = true)?

@Unique ne peut pas être testé au niveau Java de manière fiable mais pourrait générer une génération de contrainte unique de base de données. @Unique ne fait pas partie des spécifications BV aujourd'hui.

Donc, bien que je convienne qu'il serait agréable d'avoir des violations de contraintes uniques (et non nulles) enveloppées dans une exception de validation de bean, ce n'est actuellement pas le cas.

Références

52
Pascal Thivent

Plus d'informations sur la façon d'implémenter un @Unique et la problématique qui l'entoure peuvent être trouvées ici - http://community.jboss.org/wiki/AccessingtheHibernateSessionwithinaConstraintValidator

5
Hardy

Eh bien, vous POUVEZ le faire, mais ce n'est pas anodin. Le problème est le suivant: le validateur nécessite un accès à la base de données pour effectuer certaines requêtes afin de vérifier si la valeur que vous souhaitez insérer est déjà là ou non. Et cela ne peut pas vraiment être fait à partir du validateur, car il n'a pas accès à la sessionFactory/session. Bien sûr, vous pouvez l'instancier (session/sessionFactory) à l'intérieur du validateur, mais ce n'est pas une bonne pratique de codage.

3
Mateusz Dymczyk

Vous pouvez demander à un validateur de lire les annotations JPA et de les appliquer. Voici un peu un exemple d'utilisation de validateurs à ressort qui peut être utilisé comme une idée pour s'étendre.

JPA JSR303 Spring Form Validation

Vous pouvez également injecter (@Inject ou au printemps @Autowired) votre bean session dans un validateur personnalisé et le conteneur doit savoir comment le câbler. Je ne connais cela que comme un exemple de printemps:

import javax.validation.ConstraintValidator;

public class MyConstraintValidator implements ConstraintValidator {

@Autowired //@Inject
private Foo aDependency;

...
}
2
dukethrash