I have a very special case where I need to update a primary key which is disallowed by JPA (EclipseLink 2.6.0). Therefore, the entity is first deleted and then inserted with new values.
The tables involved have a predefined structure being required by GlassFish Server for JAAS authentication.
mysql> describe user_role_table;
+-------------+---------------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------------+---------------------+------+-----+---------+-------+
| user_id | varchar(176) | NO | PRI | NULL | |
| password | varchar(255) | NO | | NULL | |
| row_version | bigint(20) unsigned | NO | | 0 | |
+-------------+---------------------+------+-----+---------+-------+
3 rows in set (0.00 sec)
mysql> describe group_table;
+---------------+---------------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+---------------+---------------------+------+-----+---------+-------+
| user_group_id | varchar(176) | NO | PRI | NULL | |
| group_id | varchar(15) | NO | PRI | NULL | |
| row_version | bigint(20) unsigned | NO | | 0 | |
+---------------+---------------------+------+-----+---------+-------+
3 rows in set (0.01 sec)
user_group_id
and group_id
together form a composite primary key. group_id
in group_table
is a foreign key referencing user_id
in user_role_table
. GroupTable
holds an @EmbeddedId
from an @Embeddable
class, GroupTablePK
.
This information will seldom be needed. Therefore, I am not posting the entity classes involved.
An update is attempted to be simulated by first removing the supplied entity, GroupTable
and then persisting the same entity using a new value of group_id
as follows (in an EJB using CMT).
Again, this is a very special case and even updating a user's authority is fairly rare. Just that it is worth providing the functionality beforehand.
public GroupTable update(GroupTable groupTable, String userId, String oldGroupId) {
String newGropuId = groupTable.getGroupTablePK().getGroupId();
groupTable.getGroupTablePK().setGroupId(oldGropuId);
if (delete(groupTable)) {
// entityManager.flush();
groupTable.setUserRoleTable(entityManager.getReference(UserRoleTable.class, userId));
groupTable.getGroupTablePK().setGroupId(newGropuId);
entityManager.persist(groupTable);
}
return groupTable;
}
public boolean delete(GroupTable groupTable) {
groupTable.setUserRoleTable(entityManager.getReference(UserRoleTable.class, groupTable.getUserRoleTable().getUserId()));
GroupTable managedGroupTable = entityManager.merge(groupTable);
managedGroupTable.getUserRoleTable().getGroupTableList().remove(groupTable);
entityManager.remove(managedGroupTable);
return !entityManager.contains(managedGroupTable);
}
These methods are executed in the same transaction and they do their job pretty well but only if the only commented line inside the update()
method is uncommented. Otherwise, it complains about a duplicate entry for a primary key in the group_table
- the entity which is to be removed first is not removed prior to persisting that entity causing a duplicate insert to spawn.
Why is entityManager.flush();
required prior to persisting the entity? It is an additional round trip to the database and should be avoided.