There is entity A referring (many-to-one) entity B, with inverse (mapped-by) reference from B to A. Also there is reference A to C and inverse reference C to A. When I issue
Take a look at this answer. Basically, JPA specification mandates that a removed entity becomes managed again if the persist operation is applied to it.
To verify that this is really happening, enable the trace log level for org.hibernate
package and search for log entries like:
un-scheduling entity deletion ...
To avoid any unpredictable behaviour, it is recommended that references to removed entities are removed from all the other entity instances that are loaded the same session/transaction.
I got this issue. Even though the show_sql was enabled:
<property name="hibernate.show_sql" value="true"></property>
there was no output and the remove command was silently ignored.
The issue was around an OneToMany relation where: todo 1 --- * todoitem
The environment was: - JSF - Wildfly 18 (JPA default implementation - Hibernate) - PostgreSQL 10
Attempt to delete an instance on any side fails silently, without having the respective "delete" command on the server's output and no exception message of any type.
SOLUTION
First, I switched the many side's code suggested by the Wildfly18/JBoss documentation in its examples from:
// @Override
// public void delete(Todoitem todoitem) {
// if (todoitem == null) {
// return;
// }
// if (!emPg.contains(todoitem)) {
// todoitem = emPg.merge(todoitem);
// }
// emPg.remove(todoitem);
// emPg.flush();
// emPg.clear();
// }
To an equivalent form:
@Override
public void delete(Todoitem todoitem) {
if (todoitem == null) {
return;
}
Todoitem ti = emPg.find(Todoitem.class, todoitem.getId());
if(ti == null) {
return;
}
emPg.remove(ti);
emPg.flush();
emPg.clear();
}
Unfortunately, I got the same result - removal silently ignored.
Then, I suspected of the database, since hibernate handles its own keys. I had done many tests during implementation... To be sure about the consistency issues, I've decided to empty the database deleting the content of both sides of the relation. Then I created new entity instances and relations using the application's resources (no SQL command) since everything was working well except for entity removal. After, I checked the database relations using SQL command to make sure everything was fine, and it was.
Next, I tried a new test again but this time it was successful.
Then I reverted the code, uncommenting the commented code and vice-versa and tested again. The test failed again, returning same result — silently ignoring remove.
I set back the code to the previous condition testing again to confirm results. The confirmations was successful, confirming suspicion of two issues, database and code implementation.
Since good news, I repeated the same to the "One" side (code below - the commented code is the initial one inherited from Wildfly 18 documentation, as above mentioned).
From:
// @Override
// public void delete(Todo todo) {
// if(todo == null) {
// return;
// }
// if (!emPg.contains(todo)) {
// todo = emPg.merge(todo);
// }
// //todoitemDao.deleteAll(todo);
// emPg.remove(todo);
// emPg.flush();
// }
To:
@Override
public void delete(Todo todo) {
if (todo == null) {
return;
}
Todo t = emPg.find(Todo.class, todo.getId());
if(t == null) {
return;
}
emPg.remove(t);
emPg.flush();
emPg.clear();
}
Repeated the test again, but this time no to remove a Todoitem instance ("many" side) but to remove a Todo instance ("one" side).
Issue solved. Success.
IMPORTANT NOTE:
Check the removal tests by using the SQL statements straight on the database. Sometimes the instance seems not being removed due to cache issue or code implementation fault, requiring to be treated apart.