Managing changes to a status field through child objects

Hi,
I am running into trouble when I want the status of a parent object be changed by creating or modifying child objects.

The scenario is to make the parent object move to the ‘in progress’ status when a child object is being set to go into execution.

The status fields on both the parent and the child object are editable for the user, but I want to ‘automate’ some status changes as well.

On the ‘save’ of the child object, I added this code to modify the parent:


    public void onBtnSaveClick() {
        // Get child and parent
        Child c = cDs.getItem();
        Parent cParent = c.getParent();

        // Depending on the status of the child, update status of parent
        if (cParent != null) {
            switch (c.getStatus()) {
                case InProgress:
                    cParent.setStatus(Status.Started);
                    break;
                case Completed:
                    cParent.setStatus(Status.Completed);
                    break;
                default:
                    // Do nothing
                    break;
            }
        }

        // Save changes to parent..
        CommitContext cc = new CommitContext().addInstanceToCommit(cParent);
        dm.commit(cc);

        // Now we can safe and close the child
        super.commitAndClose();
    }

This works fine initially when editing the parent, then edit the child, returning to the parent: status has changed according to the conditions in code. However, when saving the parent there is an error saying that the object was altered in a different scope. And also, when re-editing the child, the same error occurs.

I am probably doing this the wrong way but I haven’t found a better solution. I considered using a service but it has the same drawbacks (and not refreshing the status on the parent during editing).

Any ideas or suggestions on how to implement this are much appreciated!

The problem is that when you send Parent to commit, middleware increments version field in the object for optimistic locking. In fact, the instance with the new version is returned back to the client as a result of the DataManager.commit() call, but you ignore it.

A possible solution would be either to pass the returned set of entities back to the Parent’s editor screen and call ((DatasourceImplementation) datasource).committed(committedEntities), or don’t commit Parent at all and leave it until it will be committed in its own editor. So it depends on how your screens work: is it a composition or independent editors.

Hi Konstantin.

In this case, there are two options; the ‘child’ object can be accessed through the parent’s editor but can also be edited independently. I guess that complicates stuff a bit.

Also, at first I didn’t save the parent info but then changes were not reflected in the parents’ editor.

By the way, the child objects are linked to the parent through composition.

I am still not sure how to solve this. Can you share a little more info on which way this should be implemented?

If it’s a composition, you certainly should not save parent in the middle of editing. In fact, your Child entity may not come to the database at all, because when you click OK in its editor, it is still in memory and is saved only when you save Parent entity.

You can easily pass the Parent instance to the Child editor and modify it there. The visual componets on the Parent’s screen will reflect changes.

For example:


public class ParentEdit extends AbstractEditor<Parent> {

    @Named("childrenTable.create")
    private CreateAction childrenTableCreate;

    @Named("childrenTable.edit")
    private EditAction childrenTableEdit;

    @Override
    protected void postInit() {
        Map<String, Object> params = ParamsMap.of("parent", getItem());
        childrenTableEdit.setWindowParams(params);
        childrenTableCreate.setWindowParams(params);
    }
}

public class ChildEdit extends AbstractEditor<Child> {

    @WindowParam(required = true)
    private Parent parent;

    @Override
    protected boolean preCommit() {
        Child child = getItem();
        parent.setStatus(child.getStatus());
        return true;
    }
}

The whole project is attached.

sample.zip (29.7K)

Excellent - worked perfectly!