Deep Composition

Following the 5.8.3.2. Deep Composition example all works well. But in the MeetingPoint Edit Screen, if I create new declarative nested datasources for meetingPointDs (would be airportDs and terminalDs), I receive :


java.lang.IllegalStateException: During synchronization a new object was found through ...

Why I receive this exception?. How could I use those parents datasources (airportDs and terminalsDs) from MeetingPointEdit?

Thanks.

Hi,
To create datasources nested on the meetingPointDs, the meetingPointDs should be based on the view which includes required fields.
Look at the attached project. It illustrates how the Airport and Terminal could be accessed from the Meeting point browser and editor by the use of nested datasources.

DeepCompositionTemplate.zip (38.5K)

1 Like

It throws again


java.lang.IllegalStateException: During synchronization a new object was found through ...

when you create a new Airport, a new Terminal (using the table terminalsTable CreateAction) and a new MeetingPoint (using the meetingPointsTable CreateAction).
How could I fix this?

Perhaps this is not the right approach.

Should I use the meetingPointDs.getItem() methods ( getTerminal() and getTermianl().getAirport() ) instead of terminalDs and airportDs , and remove these nestedDatasources?
In this case, when I create an Airport, a Terminal and a MeetingPoint and the three are in [new] state, changes over Terminal name are reflected when I open my modified meetingPointEdit screen, but not when the state is [detached].

Step by step:
First, when Entity state is [new]:

  1. Create new Airport, inside create new Terminal, inside create new MeetingPoint. (set all Entities name field)
  2. Commit MeetingPoint.
  3. Edit TerminalName.
  4. Open MeetingPointEdit. meetingPointDs.getItem().getTerminal.getTermName() its the previously changed.
  5. Commit MeetingPoint, commit Terminal, and commit Airport.

Second, when Entity state is [detached]:

  1. Open AirportEdit, open TerminalEdit and change TerminalName.
  2. Open MeetingPointEdit. meetingPointDs.getItem().getTerminal.getTermName() its not the previously changed.

This is my modified meetingPointEdit screen:


<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<window xmlns="[url=http://schemas.haulmont.com/cuba/window.xsd]http://schemas.haulmont.com/cuba/window.xsd"[/url];
        caption="msg://editCaption"
        class="com.company.deepcompositiontemplate.web.meetingpoint.MeetingPointEdit"
        datasource="meetingPointDs"
        focusComponent="fieldGroup"
        messagesPack="com.company.deepcompositiontemplate.web.meetingpoint">
    <dsContext>
        <datasource id="meetingPointDs"
                    class="com.company.deepcompositiontemplate.entity.MeetingPoint"
                    view="meetingpoint-terminal-airport-view"></datasource>
    </dsContext>
    <layout expand="windowActions"
            spacing="true">
        <fieldGroup id="fieldGroup"
                    datasource="meetingPointDs">
            <column width="200px">
                <field id="mpName"
                       caption="MP Name"></field>
            </column>
        </fieldGroup>
        <pickerField caption="Terminal"
                     datasource="meetingPointDs"
                     property="terminal"></pickerField>        
        <frame id="windowActions"
               screen="editWindowActions"></frame>
    </layout>
</window>

Solved setting “dirty” terminalDs datasource when terminalName changes.


public class TerminalEdit extends AbstractEditor<Terminal> {
    @Named("fieldGroup.termName")
    private TextField termNameField;
    @Inject
    private Datasource<Terminal> terminalDs;
    @Override
    public void init(Map<String, Object> params) {
        terminalDs.setAllowCommit(true);
        termNameField.addValueChangeListener(e -> {
            ((DatasourceImplementation) terminalDs).setModified(true);
        });
        super.init(params);
    }
}

Exists a better solution?
Thanks.

The last solution not works well.

I can access to the parent datasource of the next way:


    public class MeetingPointEdit extends AbstractEditor<MeetingPoint> {

    @Inject
    private Datasource<MeetingPoint> meetingPointDs;

    @Override
    protected void postInit() {
        if(getParentDs() instanceof NestedDatasource) {
            Datasource<Terminal> t = ((NestedDatasource) getParentDs()).getMaster();
            System.out.println(t.getItem().getTermName()); /*This work*/
        }
        System.out.println( meetingPointDs.getItem().getTerminal().getTermName() );  /*This no work*/
        super.postInit();
    }
}

This is the only manner I can do it.
Please, any suggestions?

Ismael,
You are right - nested datasources for parents break the deep composition editing.
So if you want to show parents on the bottom level of the composition (MeetingPoint.terminal, MeetingPoint.terminal.airport), you have to assign values to visual components directly:


<textField id="terminalName"
           caption="Terminal"
           editable="false"></textField>
<textField id="airportName"
           caption="Airport"
           editable="false"></textField>

public class MeetingPointEdit extends AbstractEditor<MeetingPoint> {
    @Inject
    protected TextField terminalName;
    @Inject
    protected TextField airportName;

    @Override
    protected void postInit() {
        terminalName.setValue(getItem().getTerminal().getTermName());
        airportName.setValue(getItem().getTerminal().getAirport().getAirportName());
    }
}

This will work for read-only fields, which I think is acceptable for the workflow when a user edits the whole composition: airport, then terminals, then meeting points. If you need a separate workflow, when a user can have a plain list of all meeting points from all airports, and is able to redefine parents for meeting points, use a separate edit screen for meeting points with nested datasources.

The working demo project is attached. I also fixed one more thing in it - the root editor (Airport) must contain the nested datasources for the whole composition including meeting points, even though it does not use meeting points datasource itself.

DeepCompositionTemplate.zip (37.8K)