Hibernate entity property does not persist in database despite flash and transaction

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?

+6
source share
2 answers

I am looking at a specification regarding the semantics of a merge operation.

Any of these scenarios can explain the cause of your problem (or maybe not):

The semantics of the merge operation applied to object X are as follows:

  • If X is a separate entity, state X is copied to a pre-existing instance of managed entity X 'of the same identifier or a new managed instance of X' from X.
  • If X is a new entity instance, a new instance of managed entity X 'is created, and state X is copied to a new instance of managed entity X'.
  • If X is an instance of a remote entity, an IllegalArgumentException will be thrown using the merge operation (or the transaction commit will fail).
  • If X is a managed entity, it is ignored by the merge operation, however, the merge operation is cascaded for objects referenced by relations from X if these relations were annotated with the cascade value of the element cascade = MERGE or cascade = ALL.
  • If X is an entity merged with X ', with a reference to another object Y, where cascade = MERGE or cascade = ALL is not specified, then navigation of the same association from X' gives a reference to the managed object Y 'with the same constant identity as Y

The save provider should not merge fields marked with LAZY that were not selected: they should ignore such fields when merging.

+1
source

I am sure this is not a solution to your problem, but I must add that your forceCommit () is working in the wrong order.

First you must use flush () to write to the database, then you commit the transaction. (That is, if you need a flash at all.)

0
source

All Articles