Проверка Bean: Получите EntityNotFoundException, хотя есть ограничение для проверки сущности - PullRequest
0 голосов
/ 01 февраля 2011

Технологии: Spring, Hibernate, JSR-303, JQuery
Платформа: Windows
Я пытаюсь реализовать ограничение @IdMustExist JSR-303.Цель ограничения - проверить, существует ли введенное значение идентификатора в связанной таблице.См. Эту ссылку для фрагментов кода IdMustExist.java и IdMustExistValidator.java.

Сценарий 1 - введено допустимое значение Id: в этом случае, когда выполняется операция EntityManager.merge hibernate,Я вижу, что ограничение @IdMustExist выполняется.Он успешно подтверждает, что введенное значение Id существует в другой связанной / связанной таблице.Hibernate успешно завершает операцию сохранения.Я заметил, что hibernate запускает SQL для объекта перед вызовом валидатора для @ IdMustExist.

Сценарий 2. Введено неверное значение Id: в этом случае при выполнении операции EntityManager.merge в hibernate выбрасывается EntityNotFoundException (трассировка стека, приведенная ниже), так как не удалось найти объект для введенного неверного идентификатора.Я надеялся, что ограничение @IdMustExist будет запущено на этапе предварительного обновления, и мы сможем изящно показать сообщение об ошибке пользователю.Но, похоже, что-то не получается, прежде чем hibernate может перейти в стадию предварительного обновления.Я вижу, что hibernate запускает SQL для объекта, а затем выдает исключение EntityNotFoundException.У него нет возможности вызвать validate @ IdMustExist.

Означает ли это, что я не могу проверить, существует ли введенный Id в связанной / связанной таблице через JSR-303?Любые альтернативы?

Спасибо за вашу помощь заранее.JP

javax.persistence.EntityNotFoundException: Unable to find com.mycompany.myapp.domain.package1.Class1 with id 100
at org.hibernate.ejb.Ejb3Configuration$Ejb3EntityNotFoundDelegate.handleEntityNotFound(Ejb3Configuration.java:133)
at org.hibernate.event.def.DefaultLoadEventListener.load(DefaultLoadEventListener.java:233)
at org.hibernate.event.def.DefaultLoadEventListener.proxyOrLoad(DefaultLoadEventListener.java:285)
at org.hibernate.event.def.DefaultLoadEventListener.onLoad(DefaultLoadEventListener.java:152)
at org.hibernate.impl.SessionImpl.fireLoad(SessionImpl.java:1080)
at org.hibernate.impl.SessionImpl.internalLoad(SessionImpl.java:1028)
at org.hibernate.type.EntityType.resolveIdentifier(EntityType.java:623)
at org.hibernate.type.EntityType.resolve(EntityType.java:431)
at org.hibernate.type.EntityType.replace(EntityType.java:291)
at org.hibernate.type.TypeFactory.replace(TypeFactory.java:532)
at org.hibernate.event.def.DefaultMergeEventListener.copyValues(DefaultMergeEventListener.java:495)
at org.hibernate.event.def.DefaultMergeEventListener.entityIsDetached(DefaultMergeEventListener.java:423)
at org.hibernate.event.def.DefaultMergeEventListener.onMerge(DefaultMergeEventListener.java:234)
at org.hibernate.event.def.DefaultMergeEventListener.onMerge(DefaultMergeEventListener.java:84)
at org.hibernate.impl.SessionImpl.fireMerge(SessionImpl.java:859)
at org.hibernate.impl.SessionImpl.merge(SessionImpl.java:843)
at org.hibernate.impl.SessionImpl.merge(SessionImpl.java:847)
at org.hibernate.ejb.AbstractEntityManagerImpl.merge(AbstractEntityManagerImpl.java:682)
at com.mycompany.myapp.dao.hibernate.package2.HibernateClass2Dao.save(HibernateClass2Dao.java:101)
at com.mycompany.myapp.service.package2.Class1ServiceImpl.update(Class1ServiceImpl.java:56)
    ...
    ...
at java.lang.Thread.run(Thread.java:619)

HibernateClass2Dao.java

    public void save(GenericRequest request, GenericResponse response){
    Class2 class2Request = (Class2) request.getObject(Class2.class.getName());
    EntityManager em = PersistenceUtil.getEntityManagerFactory().createEntityManager();
    Class2 class2Persisted = em.find(Class2.class, class2Request.getId());
    EntityTransaction tx = em.getTransaction();
    try {
        tx.begin();
        class2Persisted.setClass1(class2Request.getClass1());
        em.merge(class2Request);
        tx.commit();            
    } catch (RollbackException rbe) {
        response.setSuccess(false);
        rbe.getCause().printStackTrace();
        ConstraintViolationException cve = (ConstraintViolationException) rbe.getCause();
        Set<ConstraintViolation<?>> constraintViolations = cve.getConstraintViolations();
        if (constraintViolations.size() > 0){
            for (ConstraintViolation<?> violation : constraintViolations){
                Iterator<Node> itr = violation.getPropertyPath().iterator();
                String propertyPath = itr.next().getName();
                Class<? extends Payload> payload = violation.getConstraintDescriptor().getPayload().iterator().next();
                String payloadName = payload.getCanonicalName();                
                response.addMessage(violation.getMessage(), violation.getLeafBean().getClass().getName(),
                        propertyPath , payloadName);            
            }
        }
    } finally {
        em.close();         
    }
}

Class2ServiceImpl.java

    public void update(GenericRequest request, GenericResponse response){
    class2Dao.save(request, response);
}

Class2Controller.java

    @RequestMapping(value="/update")
public @ResponseBody GenericResponse update(String jqGridId, String oper
            , Class2 class2
            , BindingResult bindingResult) throws Exception {
    GenericResponse response = new GenericResponse(true);
    response.setMessageSource(messageSource);
    Locale locale = new Locale(CommonConstants.DEFAULT_LOCALE);
    if (bindingResult.hasErrors()){
        response.setSuccess(false);
        addBindingMessages(response, bindingResult, locale);
        return response;
    }
    class2.setId(Long.parseLong(jqGridId));
    class2.setCode(jqGridId);
    GenericRequest request = new GenericRequest(UserUtil.getUser(), class2);
    this.class2Service.update(request, response);
    return response;        
}   

Ответы [ 2 ]

1 голос
/ 02 февраля 2011

Ваша ссылка не показывает код для DAO, но я предполагаю, что вы используете метод load() из Session. См. Javadoc:

Возвращает постоянный экземпляр данного класса сущностей с заданным идентификатором, предполагая, что экземпляр существует.

Обратите внимание на ту часть, в которой написано «предполагая, что экземпляр существует». Значит, вы знаете , что какая-то сущность существует, и вы просите Hibernate загрузить ее. Если он не существует, это предположение нарушается, и выдается исключение.

То, что вы можете захотеть, это использовать метод get() вместо этого. Посмотрите, что говорит Javadoc:

Возвращать постоянный экземпляр заданного класса сущностей с заданным идентификатором или ноль, если такого постоянного экземпляра нет.

Итак, решение состоит в том, чтобы перейти с load() на get().

Javadoc: http://docs.jboss.org/hibernate/core/3.5/api/org/hibernate/Session.html

0 голосов
/ 05 февраля 2011

Несколько вещей здесь.Что Session используется вашим CommonDao .На самом деле это должен быть новый сеанс, открытый на текущем соединении.Вся проблема, связанная с использованием сеанса (или менеджера сущностей в валидаторе ограничений), обсуждается в вики Hibernate Validator: http://community.jboss.org/wiki/AccessingtheHibernateSessionwithinaConstraintValidator

Хотя я не рекомендую этот подход.Я бы просто позвонил merge и имел дело с исключениями Hibernate Core (или JPA).

...