Estou desenvolvendo um sistema, e pintou a seguinte dúvida, no uso do Hibernate (JPA):
Qual a exceção é lançada quando ocorre uma violação de constraint? No caso um dos atributos da minha Entity tem as seguintes constraints: @Column(name = “nome”, nullable = false, unique= true)
O banco de dados está obedecendo corretamente às constraints… A dúvida é para o tratamento das Exceptions, e mostar ao usuário mensagens amigáveis:
No caso de tentar : entityManager.persist(entity); é lançada a exceção javax.persistence.EntityExistsException… Neste ponto está OK… Estou tratando corretamente…
Agora quando tento: entityManager.merge(entity);é disparada uma exceção diretamente pelo Hibernate (org.hibernate.exception.ConstraintViolationException: Could not execute JDBC batch update )… Para não tornar meu código amarrado ao Hibernate, qual exceção eu deveria capturar neste caso??
Eu nao posso te afirmar com 100% de certeza, mas acho que ConstraintViolationException é lancada quando ocorre erro de constraint no banco. Talvez seja alguma que esteja “escapando” do tratamento no mapeamento, mas que esteja no BD.
Tente ver qual a exception que causa o erro, a mensagem deve indicar onde esta o problema.
Eu inseri um registro no banco
Depois alterei um outro registro, de modo que o valor do campo “nome” ficasse igual ao primeiro registro… Como existe a constraint UNIQUE, o banco de dados não deixou que o UPDATE ocorresse… Esse era o comportamento esperado mesmo…
Essa é uma situação que pode ocorrer no “mundo real”… O usuário tentar dar update em uma Entity e acabar esbarrando em uma constraint… Então precisamos tratar isso de forma apropriada, para exibir mensagens de erro coerentes…
Não estou encontrando uma forma funcional de capturar essa Exception… O ideal seria ter uma Exception do proprio javax.persistence… Amarrar numa exceção do Hibernate não é legal, porque o código vai ficar dependente do Hibernate… A idéia do JPA é justamente permitir a troca do Persistence Provider, então não faz muito sentido eu amarrar em uma Exception do Hibernate…
Eu nao sei pq nunca trabalhei somente com JPA, mas acho estranho ela nao ter um “wrapper” para essa exception.
O que voce poderia fazer é ver a possibilidade de pegar as excecoes desse tipo num ponto comum e lancar uma excecao “customizada”, dessa forma apenas uma pequena parte do codigo estaria atrelado ao hibernate e nas camadas superiores vc faria referencia a essa sua excecao. Isso contornaria o problema, pelo menos até uma solucao da JPA.
Eu ainda fico realmente impressionado com este tipo de coisa. A pergunta do colega foi clara, direta, prática e objetiva e, infelizmente, as respostas passam bem longe; além de retóricas, são evasivas.
Mesmo assim, ainda vou esperar alguma resposta inteligente de algum gurú que realmente consiga entender perguntas pois estou também com esta dúvida.
Galera desculpa ressuscitar o tópico mas é porque eu encontrei uma solução depois de horas e horas de pesquisa no google e dei uma modificada pra funcionar do jeito que eu necessitava, vou deixar aí pra caso alguem precise:
no meu método da classe controller/DAO/onde faço o persist no entity manager coloquei throws Exception e coloquei um try catch com esse catch:
catch (PersistenceException e) {
Throwable t = e;
boolean cont = true;
while (t != null) {
if (t.getMessage().startsWith("Duplicate entry")) {
cont = false;
throw new Exception("Duplicate entry");
}
t = t.getCause();
}
if (cont) {
throw new Exception(e.getMessage());
}
}
e la no meu managedbean coloquei o seguinte catch no metodo salvar:
catch (Exception e) {
if (e.getMessage().trim().startsWith("Duplicate entry")) {
Msg.show("Cpf/Cnpj está repetido!");
} else {
Msg.show("Erro ao Salvar");
e.printStackTrace();
}
}