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.