2016-06-02 5 views
0

을 발생합니다하지만 난 내 인생은 무슨 일이 일어나고 있는지 이해할 수 없다 위해. 행운이없이 몇 시간 동안 웹에서 답변을 찾고있었습니다.하는 검증은 통과하지만 병합()가 호출 될 때 유효성 검사 오류는 여기 질문에 대한 죄송합니다

나는 단순한 퀴즈를 JPA에서 모델링했으며, WildFly 10.0.0에서 실행되는 VRaptor (MVC 프레임 워크)를 사용했다. Hibernate 5.0.7.Final을 사용하는 최종 서버. 퀴즈에는 2-10 대체품이있는 많은 질문이 있습니다.

나는 현재 사용자가 추가/퀴즈에 대한 질문을 제거하기위한 방법을 구현하고있다. merge(quiz)을 호출하기 전에 유효성 검사를 실행하여 모든 것이 유효한지 확인합니다. 그것은 통과합니다. 나는 오류가 없다. 유효성 검사 오류가 없기 때문에

, 나는 merge(quiz) 전화 마침내 나는 다음과 같은 예외로 인사 해요 :

javax.validation.ConstraintViolationException: Validation failed for classes [game.Question] during persist time for groups [javax.validation.groups.Default, ] 
List of constraint violations:[ 
    ConstraintViolationImpl{interpolatedMessage='Cannot be empty', propertyPath=alternatives, rootBeanClass=class game.Question, messageTemplate='{org.hibernate.validator.constraints.NotEmpty.message}'} 
] 

[편집] 내가 의도적으로 빈 뭔가를 떠날 경우 유효성 검사 오류를 보여 아무튼 않습니다 ' t merge()을 시도하면 유효성 검사가 예상대로 실행됩니다.

나는 모든 것을 수동으로 검사 했으므로 오류가 없습니다.

@Transactional 
public void updateQuestions(final String quizId, final List<Question> questions) { 
    // Quizzes might have slugs (/quiz-name) 
    final Quiz quiz = findQuizByIdString(quizId); 
    if (quiz != null) { 
     for (final Question question : questions) { 
      question.setQuiz(quiz); 

      if (question.getAlternatives() != null) { 
       for (final Alternative alt : question.getAlternatives()) { 
        alt.setQuestion(question); 
       } 
      } 

      if (question.getId() != null) { 
       final Question old = (Question) ps.createQuery("FROM Question WHERE id = :id AND quiz = :quiz").setParameter("id", question.getId()).setParameter("quiz", quiz).getSingleResult(); 

       // Making sure the Question do belong to the this Quiz 
       if (old == null) { 
        question.setId(null); 
       } 
      } 

      if (question.getId() == null) { 
       // Set the new question up (who created, timestamp, etc.) 
      } 
     } 

     quiz.setQuestions(questions); 

     if (!validator.validate(quiz).hasErrors()) { 
      try { 
       entityManager.merge(quiz); 
      } catch (final Exception e) { 
       if (log.isErrorEnabled()) { log.error("Error while updating Quiz Questions", e); } 
      } 
     } 
    } 
    else { 
     // Send an error to the user 
    } 
} 

를 마지막으로 이러한 (내 생각)과 관련된 다음과 같습니다

private void val(final Object obj, final String s) { 
    final ValidatorFactory factory = Validation.buildDefaultValidatorFactory(); 
    final javax.validation.Validator validator = factory.getValidator(); 
    final Set<ConstraintViolation<Object>> constraintViolations = validator.validate(obj); 
    for (final ConstraintViolation cv : constraintViolations) { 
     log.info("-------------"); 
     log.info(s + " ValidatationConstraint: " + cv.getConstraintDescriptor().getAnnotation()); 
     log.info(s + " ValidatationConstraint: " + cv.getConstraintDescriptor()); 
     log.info(s + " ValidatationConstraint: " + cv.getMessageTemplate()); 
     log.info(s + " ValidatationConstraint: " + cv.getInvalidValue()); 
     log.info(s + " ValidatationConstraint: " + cv.getLeafBean()); 
     log.info(s + " ValidatationConstraint: " + cv.getRootBeanClass()); 
     log.info(s + " ValidatationConstraint: " + cv.getPropertyPath().toString()); 
     log.info(s + " ValidatationConstraint: " + cv.getMessage()); 
     log.info("-------------"); 
    } 
} 

이 내 추가/제거 질문 방법이 할 약 것입니다 : 확인 및 인쇄 유효성 검사 오류는이 "대안"방법을 사용 내 조직의 일부 :

@Entity 
public class Quiz { 
    /* ... */ 
    @Valid // FYI: This just makes the validation cascade 
    @OneToMany(mappedBy = "quiz", cascade = CascadeType.ALL, fetch = FetchType.EAGER, orphanRemoval = true) 
    private List<Question> questions; 
    /* ... */ 
} 

@Entity 
public class Question { 
    /* ... */ 
    @Valid 
    @NotEmpty 
    @Size(min = 2, max = 10) 
    @OneToMany(mappedBy = "question", cascade = CascadeType.ALL, fetch = FetchType.LAZY, orphanRemoval = true) 
    private List<Alternative> alternatives; 
    /* ... */ 
} 

@Entity 
public class Alternative { 
    /* ... */ 
    @NotBlank 
    @Size(max = 0xFF) 
    @Column(length = 0xFF, nullable = false) 
    private String text; // The only field that must be filled 
    /* ... */ 
} 

답변

0

알 수 있습니다. 친구가 merge() 이전의 새 질문에 persist()을 사용하도록 제안했습니다.

그는 merge() 새로운 엔티티를 생성하지 않기 때문에 그는 것이라고 말했다 있지만. 엔티티가 존재하지 않으면 JPA 스펙에 따라 새로운 인스턴스가 지속성 컨텍스트에 작성되고 원래는 이됩니다.이 복사됩니다.

복사본은 Java에서 모든 생명의 위협입니다. 질문의 모든 인스턴스 (List 엔티티하지 않거나 사본이 얕은 단순히 때문에 때문에 아마 알고까지로)이 복사되지 않았습니다 대안 의 배열 (List의 인스턴스)를 가지고 있기 때문에.

음, 어쨌든 도움이 미래에 부딪 칠 수있는 사람에게 아주 좋은 행운을 시도 사람에게 감사합니다.

[편집] 문제는 복사가 수행 JPA 때문이었다. QuizList<Question>이므로 복사 할 예정입니다. 이유는 무엇입니까? (얕은 사본?)List<Alternative>Question은 복사되지 않았습니다. 그렇기 때문에 alternatives 필드에서 @NotEmpty 유효성 검사가 실패한 이유가 Question입니다.

병합하기 전에 각 Questionpersist()을 호출하면 그것들이 지속성 컨텍스트에 포함되며 더 이상 복사본이 필요하지 않습니다.

for (int i = 0, max = questions.size(); i < max; i++) { 
    Question question = questions.get(i); 

    /* all of that previous code */ 

    if (question.getId() == null) { 
     entityManager.persist(question); 
    } 
    else { 
     /* merge() returns the newly merged and managed (as in it is now part of 
      the persistence context) instance, so replace the "old" one */ 
     questions.set(i, entityManager.merge(question)); 
    } 
} 
:

이를 수행하여나요