Check against transient attribute in entity listener fails

Hi,

In my scenario I have an entity (lets call it A) with a number of related entities of a different entity type (lets call them B). Thier relation is set by a many-to-many association. So A can relate to multiple B’s and the other way around as well.

In some cases, when there is a change in a B entity, the status in A needs to change as well. This is taken care of primarily through an entity listener on B to reflect required changes on A when needed. This works well.

However, the editor of A lists related entities of B and it is possible to change a B entity such that A needs to change as well (as stated above). To relfect this behaviour to the user immediately, this change is also applied in the editor of A before commiting any changes. Again, this works well up to this point.

However, when this setup is now commited (saved), the listener on B triggers to change A + merging it (em.merge()), then later the platform commits A and finds the A entity changed and will therefore throw an exception:

The object [A [detached]] cannot be merged because it has changed or been deleted since it was last read

This makes sense and is not the issue I have. To overcome this problem, I added a transient attribute (leaveA) on B to indicate that the listener should not trigger when used from the editor A. Thus, the editor for A sets this property on entities B to prevent the listener from triggering.

Previously this seemed to work well. The listener checked against leaveA being false and would not trigger if otherwise. It seems that after some platform updates (I am not sure when) this behaviour is not applicable anymore. Somehow, the transient attribute (leaveA) is always false although set to true in the editor.

I have traced the cause of this behaviour back to the com.haulmont.cuba.core.app.RdbmsStore class, line 398:

...
            // merge the rest - instances can be detached or not
            for (Entity entity : context.getCommitInstances()) {
                if (!entityStates.isNew(entity)) {
                    if (isAuthorizationRequired(context)) {
                        security.assertToken(entity);
                    }
                    security.restoreSecurityStateAndFilteredData(entity);
                    if (isAuthorizationRequired(context)) {
                        attributeSecurity.beforeMerge(entity);
                    }

                    Entity merged = em.merge(entity);
                    saved.add(merged); // This is line 398

                    entityFetcher.fetch(merged, getViewFromContext(context, entity));
                    attributeSecurity.afterMerge(merged);

                    if (isAuthorizationRequired(context))
                        checkOperationPermitted(merged, ConstraintOperationType.UPDATE);

                    if (entityHasDynamicAttributes(entity)) {
                        BaseGenericIdEntity originalBaseGenericIdEntity = (BaseGenericIdEntity) entity;
                        BaseGenericIdEntity mergedBaseGenericIdEntity = (BaseGenericIdEntity) merged;
                        mergedBaseGenericIdEntity.setDynamicAttributes(originalBaseGenericIdEntity.getDynamicAttributes());
                        entitiesToStoreDynamicAttributes.add(mergedBaseGenericIdEntity);
                    }
                }
            }

...

In that line, the merged entity (which has the transient attribute leaveA cleared) is being added to the set of saved entities which is later on used for the listener.

So the main question is:

Why is the merged entity added to the set? If the original entity was added to the set of saved entities instead, there would be no problem (for me at least).

To be clear, I am on the latest 6.10 release (migration to 7.x is still too much work at this point).

Thanks for any help or clarification on this behaviour.

Regards,
-b

Hi,

Turns out I had the transient attribute defined incorrectly. When adding the @MetaProperty all works as expected:

@Transient
@MetaProperty
protected Boolean leaveA = false;

Sorry to have borderd you with this question.

Regards,
-b