Уникальное ограничение с JPA и Bean Validation

Я хотел бы иметь ограничение @Unique с проверкой компонентов, но это не предусмотрено стандартом. Если бы я использовал @UniqueConstraint JPA, у меня не было бы уникального механизма проверки и сообщения об ошибках.

Есть ли способ определить @Unique как ограничение проверки компонента и объединить его с JPA, чтобы JPA создавал столбец с уникальным ограничением и проверял, является ли значение уникальным или нет?


person deamon    schedule 16.08.2010    source источник


Ответы (4)


Если вы не заблокируете всю таблицу, в принципе невозможно проверить уникальность с помощью SQL-запроса (любая параллельная транзакция может изменить данные после ручной проверки, но до фиксации текущей транзакции). . Другими словами, невозможно реализовать действительную уникальную проверку на уровне Java и, таким образом, обеспечить реализацию проверки. Единственный надежный способ проверить уникальность — это совершить транзакцию.

Спецификация BV резюмирует это следующим образом:

Приложение D. Интеграция Java Persistence 2.0

Вопрос: следует ли добавить @Unique, который будет отображаться в @Column(unique=true)?

@Unique не может быть надежно протестирован на уровне Java, но может сгенерировать уникальное ограничение базы данных. @Unique сегодня не является частью спецификации BV.

Поэтому, хотя я согласен с тем, что было бы неплохо иметь уникальные (и не нулевые) нарушения ограничений, завернутые в исключение проверки компонентов, в настоящее время это не так.

использованная литература

person Pascal Thivent    schedule 17.08.2010
comment
Так как же правильно проверить и сообщить пользователю, что введенное значение уже существует? Исключение (и его сообщение), выдаваемое при фиксации, не может отображаться пользователю. Люди все равно будут реализовывать свои собственные @Unique (например, здесь lucasterdev.altervista.org/wordpress/2012/07/28/), даже если существует небольшой риск того, что параллельная транзакция изменяет данные между проверкой и фиксацией. - person Adam Dyga; 05.12.2013
comment
Это кажется слишком идеалистичным. Многие другие веб-фреймворки (например, Rails, Django и т. д.) включают проверку на уникальность и сталкиваются с точно такой же проблемой. Совершенно верно, что это проблема, но она все равно должна быть доступной опцией с предупреждением. Если другие фреймворки могут справиться с этим, я не думаю, что Java настолько особенная, чтобы думать, что она выше их. - person user2490003; 28.08.2018
comment
@ user2490003 прав насчет идеализма; спасибо за этот комментарий. Уникальное ограничение СУБД — это последняя защита от введения неверных данных. Имеет смысл приложить усилия, чтобы проверить, не будет ли нарушено уникальное ограничение... и создать последовательное/удобочитаемое сообщение проверки. Стыдно за Яву. Это не 90-е. - person Dan; 04.12.2019

Дополнительную информацию о том, как реализовать @Unique и связанные с этим проблемы, можно найти здесь — http://community.jboss.org/wiki/AccessingtheHibernateSessionwithinaConstraintValidator

person Hardy    schedule 13.11.2010

Ну, вы МОЖЕТЕ это сделать, но это не тривиально. Проблема в том, что валидатору требуется доступ к базе данных для выполнения некоторых запросов, чтобы проверить, существует ли значение, которое вы хотите вставить, или нет. И это невозможно сделать из валидатора, так как у него нет доступа к sessionFactory/session. Конечно, вы можете создать экземпляр (session/sessionFactory) внутри валидатора, но это не очень хорошая практика кодирования.

person Mateusz Dymczyk    schedule 16.08.2010
comment
... и, как указал Паскаль Тивент, это может привести к проблемам параллелизма. - person deamon; 13.11.2010

Вы можете заставить валидатор читать аннотации JPA и применять их. Вот несколько примеров использования весенних валидаторов, которые можно использовать в качестве идеи для расширения.

JPA JSR303 Spring Form Validation

Вы также можете внедрить (@Inject или Spring @Autowired) свой сессионный компонент в настраиваемый валидатор, и контейнер должен знать, как его подключить. Я знаю это только как пример Spring:

import javax.validation.ConstraintValidator;

public class MyConstraintValidator implements ConstraintValidator {

@Autowired //@Inject
private Foo aDependency;

...
}
person dukethrash    schedule 06.10.2010