Pergunta

I'm doing a web project with Primefaces that sends and gets data from remote EJB that uses JPA. I got this code to handle unique values, after setting unique=true in Entity Bean:

try{
    emsave.persist(newItem);
} catch (PersistenceException pe){
    System.out.println("dupe found");
}

Then I rollback the transaction. In Eclipse console I get these messages from Jboss AS:

09:15:12,179 WARN  [org.hibernate.engine.jdbc.spi.SqlExceptionHelper] (http-localhost-127.0.0.1-8189-6) SQL Error: 1062, SQLState: 23000
09:15:12,179 ERROR [org.hibernate.engine.jdbc.spi.SqlExceptionHelper] (http-localhost-127.0.0.1-8189-6) Duplicate entry 'asdasd' for key 'username'

I have to send objects that can't be saved back to front-end and display them in a table, or mark them somehow in the table so that user knows what he has to change. I have a way how to do that, but I don't know how to mark what field has bad value. Is it possible to get that 'username' field was filled incorrectly from this exception, or some another way should be used? I'm looking for most elegant solution.

Foi útil?

Solução

First of all, persist() is not what will throw the exception. persist() only marks the object as persistent by attaching it to the persistence context. The actual insert will happen at flush time.

Second, it seems that you want to do that in a loop. All runtime exeptions are irrecoverable and leave the context in an unreliable state. As soon as you get an exception, the current transaction should be rollbacked and you shouldn't keep using the entity manager.

And finally, these two facts and common good practices lead to the solution: you shouldn't rely on exceptions to detect incorrect values. If names should be unique, then you should issue a query to test if the entered names already exist in the table, and only insert once you have validated everything. Of course, you could have a race condition between two concurrent transaction, but this situation won't happen often, and you can thus use a generic "Oops" error message to handle it (or retry the transaction if really necessary).

Outras dicas

There is no good way to do this. The problem is that JPA does not validate the DB constraints itself. It just delegates this check to underlying DB. So, the concrete exception is thrown by JDBC driver and is wrapped by PersistenceException. You can obviously call pe.getCause() (and even probably twice - see what kind of exception is thrown using debugger) and try to process the exception message. But note that this could depend on underlying DB and/or its JDBC driver.

BUT: generally it is a very bad practice to create exception based flow. You should validate your application level "constraints" yourself and just do not try to perform operation if unique constraint violation is possible. If however it happened anyway there is nothing to do: user should try to perform the operation again. User should not be able to perform "wrong" operation: UI should protect him.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top