Trouble using nested objects

Hi,

I am having some trouble working with nested objects using a composition structure. In my case, there are a number of objects that are related as such:

Main object > Composition objects > Composition objects

E.g, consider this scenario:

Meeting session > Discussion topics > Comments

Typically, when creating a new session, adding topics and for these topics adding comments, there is an error when clicking save on a newly created comment (while the discussion/meeting has not been saved before).

I have tried to avoid the error by having all fields (including system properties) in the view definition(s) used to build the screens. However, when saving the ‘topic’ to the ‘meeting’ while containing some comments, this still runs into an error:


IllegalStateException: During synchronization a new object was found through a relationship that was not marked cascade PERSIST: com.company.composition.entity.Topic-7dababc6-0128-c91b-1acc-0de41eac0068 [new].

Is there any guideline to follow and make this work consistently?

Attached is the project that shows the problem.

testproject.zip (214.4K)

Yes, there is a guideline: Deep Composition

You should declare the whole composition hierarchy under the datasource of the master entity in the root editor (meeting-edit.xml):


<datasource id="meetingDs"
            class="com.company.composition.entity.Meeting"
            view="meeting-view">
    <collectionDatasource id="topicsDs"
                          property="topics">
            <collectionDatasource id="commentsDs"
                                  property="comments"/>                          
    </collectionDatasource>
    ...
</datasource>

Hi Konstantin,

Thanks - I had read the deep composition thing earlier on and that’s an improvement. However, my actual issue is a bit more complex.

Below is the datasource definition for a risk analysis, containing risks, which contain countermeasures:

Risk analysis > Risks > Countermeasures > Comments
| | > Files
| > Files

And some supporting objects as well like files (objects that compose the sysFile combined with author, version and remars). There are also participants etc.


     <datasource id="riskAnalysisDs"
                    class="com.axxemble.base27.entity.RiskAnalysis"
                    view="riskAnalysis-view">
            <collectionDatasource id="risksDs"
                                  property="risks">
                <collectionDatasource id="cmDs"
                                      property="counterMeasures">
                    <collectionDatasource id="commentsDs"
                                          property="comments"/>
                    <datasource id="cmOwnerDs"
                                property="owner"/>
                    <collectionDatasource id="cmFilesDs"
                                          property="files">
                        <datasource id="cmSysFileDs"
                                    property="fileFile"/>
                    </collectionDatasource>
                    <collectionDatasource id="cmParticipantsDs"
                                          property="participants"/>
                </collectionDatasource>
                <collectionDatasource id="riskFilesDs"
                                      property="files">
                    <datasource id="riskSysFileDs"
                                property="fileFile"/>
                </collectionDatasource>
                <datasource id="riskOwnerDs"
                            property="owner"/>
            </collectionDatasource>
            <collectionDatasource id="participantsDs"
                                  property="participants"/>
        </datasource>

I’m pretty sure that I have all the nested objects included but still, when creating a risk analysis, including risk, including countermeasures, it fails when I want to save the countermeasure.

A bit lost here to see what is missing or what I’m doing wrong.

Currently, a composition cannot have more than 2 levels (I believe it is mentioned in the docs). So you have to split this tree at some level to separate editors or shallower compositions.

I understand that using the composition for the whole hierarchy would be simple, but it has downsides too:

  • a user spends more time editing data in memory without committing anything to the database, and there are more chances that he can accidentally lose all changes

  • deep composition can affect performance, because you load a large object graph at once but don’t actually use all its content. See some considerations here.

Hi Konstantin,

I see - that’s typically something that you do not read in a first run and later on seems irrelevant to read again :slight_smile:

Anyway, I tried to make the main object relations (analysis > risk and risk > countermeasure) as associations instead of compositions but the problem persists. I think (reading your comment in the ‘to consider’ topic you referred to) that I need to split up the data collections and views but I’m a bit lost there.

Let me try to break up the difficulty I have into single-topic questions:

  • Does an editor need to load ALL associated data from any of the objects that can be accessed from this editor, including all sub-objects? If so, when using compositions you need to nest them in the datasource definition, otherwise define them separately. Correct?
  • Does the view that is being used for the editor need to specify all properties/objects that can be access from its editor as well? So it would for a large part travers all nested information again.
  • Are there considerations to take into account for the coding perspective regarding this topic?

And still, although I’m including all data (not the most performing approach I guess), it do not get it to work… Whether I leave them nested in the datasource of the risk analysis or have them separated.

Help?

Hi Berend,

Does an editor need to load ALL associated data from any of the objects that can be accessed from this editor, including all sub-objects? If so, when using compositions you need to nest them in the datasource definition, otherwise define them separately.

Correct.

Does the view that is being used for the editor need to specify all properties/objects that can be access from its editor as well?

You don’t specify a view for the editor - you specify it for a datasource (it can be a main datasource of the editor, i.e. the one that contains the root edited entity). And the view of the datasource must contain all related objects that are used in nested datasources of this particular standalone datasource.

Are there considerations to take into account for the coding perspective regarding this topic?

I think it would be better if we prepare a sample application demonstrating possible approaches to the screens interaction in case of deep nested structures. I’ll let you know when it’s ready (in the next couple of days).

Thanx - looking forward to it!

Please see https://github.com/cuba-platform/sample-screen-manipulation#deeply-nested-structures

Hi Konstantin,

Thanks for the update. I saw the way this is handled for the airports > terminals > meeting points > notes. But both scenario’s are not really appropriate for my case (or I will have some trouble explaining the behavior.

An alternative solution that would fit in my case, is to avoid adding the lower level entities. In my case comments & files. The general way of working will be to setup a session, create a list of risk and for some identify some countermeasures. It is not expected that comments or files will be added at this point in time.

I see two approaches that I could follow: (1) reuse the countermeasure editor but somehow disable to add comments/files IF the editor is called originally from the analysis, or (2) create a different editor that excludes the comments & files and is used from the listing on risks.

Is such a scenario possible? Can it be detected somehow that the editor is called originally from the analysis or the nesting level? Can there be two different editors for the same entity?

Thanks again for your help - much appreciated.

Hi Berend,

You can do both.

In case you have a single editor, in order to find out where it was called from, you should pass a parameter from the call site. You can do it using the setWindowParams() method of “create” and “edit” actions.

Also, you can create multiple editor screens for an entity, just give them different Ids. The one named by convention entityName.edit will be invoked by default, for calling others you have to specify the Id explicitly in “create” and “edit” actions. See for example init() method in AirportEdit.

Thank you - will proceed with option #1 I guess as it is the most flexible/least annoying option for the end users I expect.