Проверяет нарушение ограничений перед тем, как сохранить объект
Каков наилучший механизм для предотвращения проверок нарушения ограничений перед созданием | модификация объекта?
Предположим, что сущность "User" имеет "loginid" как уникальное ограничение, было бы разумно проверить, есть ли пользовательская запись уже с этим именем пользователя перед созданием или модификацией.
ИЛИ
Вы позволили бы базе данных выкинуть ConstraintViolationException и соответствующим образом обработать это сообщение в слое пользовательского интерфейса. Где такие проверки должны соблюдаться в рамках швов jboss.
Примечание. В настоящее время такие проверки не выполняются в коде кода шва.
В настоящее время мы используем Seam 2.2, Richfaces с Hibernate.
Ответы
Ответ 1
Даже если вы проверяете условие в своем коде перед сохранением объекта пользователя, всегда есть вероятность, что кто-то создаст дубликат идентификатора входа между проверенным временем и при сохранении нового пользователя.
Однако будет легче отобразить соответствующее сообщение об ошибке в пользовательском интерфейсе, если вы выполните явную проверку. Если у вас есть несколько исключений в таблице, то захват ConstraintViolationException не позволит вам легко определить, какое ограничение было нарушено.
Поэтому я бы сделал и то, и другое. Предполагая, что вы расширяетесь от Seam EntityHome:
- В методе persist() запустите запрос, чтобы убедиться, что loginID уникален. Если он не добавляет сообщение об ошибке в соответствующий элемент управления и возвращает значение null.
- Оберните вызов super.persist() и поймите ConstraintViolationException, показывая общее сообщение об ошибке с дубликатом
ИЗМЕНИТЬ
Как сказал Шервин, создание JSF Validator - отличная идея (замена) # 1 выше, но вы все равно должны ожидать худшего и поймать ConstraintViolationException.
Ответ 2
Я не согласен с обработкой исключения ConstraintException. Я написал валидатор, который проверяет дубликаты перед сохранением, и он отлично работает.
Вот пример проверки дубликатов писем.
@Name("emailValidator")
@Validator
@BypassInterceptors
@Transactional
public class UniqueEmailValidator implements javax.faces.validator.Validator, Serializable {
private static final long serialVersionUID = 6086372792387091314L;
@SuppressWarnings("unchecked")
public void validate(FacesContext facesContext, UIComponent component, Object value) throws ValidatorException {
EntityManager entityManager = (EntityManager) Component.getInstance("entityManager");
String newEmail = (String) value;
String oldEmail = String.valueOf(component.getAttributes().get("oldEmail"));
if (oldEmail != null && !oldEmail.equalsIgnoreCase(newEmail)) {
List<User> users = entityManager.createQuery(
"SELECT DISTINCT u FROM " + User.class.getName() + " p where lower(p.fromEmail) = :email").setParameter("email",
newEmail.toLowerCase()).getResultList();
if (!users.isEmpty()) {
Map<String, String> messages = Messages.instance();
throw new ValidatorException(new FacesMessage(FacesMessage.SEVERITY_ERROR, messages.get("admin.emailexists"), messages
.get("admin.emailexists")));
}
}
}
}
И в вашей форме (xhtml) вы пишете:
<s:decorate template="/layout/definition.xhtml">
<ui:define name="label">#{messages['processdata.email']}</ui:define>
<h:inputText id="fromEmail" size="30" required="true" value="# {userAdmin.existingUser.fromEmail}">
<f:validator validatorId="emailValidator"/>
<f:attribute name="oldEmail" value="#{userAdmin.existingUser.fromEmail}" />
<s:validate />
</h:inputText>
</s:decorate>
Таким образом, он всегда будет проверять поле перед сохранением. Вы даже можете поставить a: тег поддержки для проверки при изменении фокуса.
Ответ 3
Мой совет заключается в том, что если вы можете проверить условие, проверьте его, например, в вашем случае вызов метода UserExists. Выбрасывание исключений является дорогостоящим и предназначено для исключительных случаев, обычно связанных с вещами, выходящими за ваше управление, например. доступ к диску и т.д.
Обычно вы выполняете эту проверку в своей бизнес-логике, прежде чем обращаться к сущности, которая будет добавлена в базу данных.