I have an Entity MXGroup that is logically deleted using the status property. This object is stored in the MySQL database through Hibernate. When I create this object using my JSF page, continue it, then try to update this status column without reloading my page between creation and logical deletion, the change in the status column will not be saved.
The entity is clearly in the Hibernate cache and in the database. Updating a property and then calling merge with it does not merge the changes into the database.
I explicitly called flush and getTransaction().commit() in my entity manager after merging the object, but still haven't bought it.
If I refresh my page (maybe I get another EntityManager , since my EntityManagers is the talk area), I can suddenly delete my MXGroup without any problems.
I know that there are workarounds that I could do, so this is pretty much an academic exercise as to why this is happening ...
My MXGroup objects are loaded via the RESTful interface via ajax in the following ways: (the PersonalGroup object extends the MXGroup object)
@GET @Produces(MediaType.APPLICATION_JSON) @Path("personal/") public Response restPersonalGroups() { return Response.ok().entity(serializePersonalGroups()).build(); } public String serializePersonalGroups() { final List<PersonalGroup> personalGroupsList = this.userGroupService.getPersonalGroups(); String personalGroups = serializeGroupList(personalGroupsList); return personalGroups; }
Using the userGroupService.getPersonalGroups() method looks like this:
public List<PersonalGroup> getPersonalGroups() { CriteriaBuilder builder = this.getEntityManager().getCriteriaBuilder(); CriteriaQuery<PersonalGroup> criteria = builder.createQuery(PersonalGroup.class); Root<PersonalGroup> root = criteria.from(PersonalGroup.class); List<Predicate> predicateList = new ArrayList<Predicate>(); predicateList.addAll(Arrays.asList(getCommonPredicates(PersonalGroup.class, builder, criteria, root))); predicateList.add(builder.equal(root.get(PersonalGroup_.user), getUser())); TypedQuery<PersonalGroup> query = this.getEntityManager().createQuery( criteria.select(root) .where(predicateList.toArray(new Predicate[predicateList.size()])) .orderBy(builder.asc(root.get(MXGroup_.name))) .distinct(true)); List<PersonalGroup> personalGroups = query.getResultList(); for (PersonalGroup pg : personalGroups) { this.getEntityManager().refresh(pg); } return personalGroups; }
getCommonPredicates in this case only adds predicate checking if status == 1
The delete function looks like this:
public void deletePersonalGroup() throws BadLoginNameException, UniqueUserLoginException { String groupIdStr = FacesContext.getCurrentInstance().getExternalContext().getRequestParameterMap().get("groupId"); int groupId = Integer.parseInt(groupIdStr); MXGroup group = this.userGroupService.findMXGroup(groupId); group.setStatus(0); this.userGroupService.mergeMXGroup(group); this.userGroupService.forceCommit(); }
with mergeMXGroup being:
@Override public void mergeMXGroup(MXGroup group) { super.merge(group); }
The super implementation is as follows:
protected <T> T merge(T entity) { if (canUseService() && beforeMergeEntity(entity)) { T merge = this.getEntityManager().merge(entity); return merge; } return null; }
And finally, I force the flash and commit as follows:
public void forceCommit() { this.getEntityManager().getTransaction().commit(); this.getEntityManager().flush(); }
The RESTful interface will almost certainly have a different object manager for the deletion code, since the deletion code is managed by CDI and the RESTful interface is managed by EJB. But I would have thought that flash and commit would solve this problem? In fact, this is the first time I have had to explicitly hide / commit in this whole project ...
Any thoughts?