TwinColumn with many-to-many relationship

Hello there.
I have two entities which share a many-to-many relationship.

Tag <—> Person

So a person can have many tags, and a tag can have many people associated with it. All good so far.
Now tags can only be selected from a predetermined list; you cannot add a new tag through an editor, so I thought that a TwinColumn would be the best to display it.

Person contains list of tags that are linked through the link table added by Cuba studio
I defined the twin column as follows:

 <twinColumn id="personTagsTwinColumn"
             addAllBtnEnabled="true"
             datasource="personDs"
             optionsDatasource="AvailableTagsDs"
             property="tags"
             responsive="true"
             width="100%"/>

Now when I add tags and save the page, the link table is correctly filled in (I’ve looked on the database and the linked records are there), but when I return to the page, the right side of the twincolumn (which should be populated by the list Person.tags) is blank.
I suspect the problem is that the TwinColumn is trying to populate from the link table, and not the actual tags.

Is this the correct use for the TwinColumn, or is there a better way to do it?

Hi,

You can use TwinColumn for this purpose. The easiest way is to bind it to a datasource, for example:

<dsContext>
    <datasource id="personDs"
                class="com.company.demo.entity.Person"
                view="person-view">
        <collectionDatasource id="tagsDs"
                              property="tags"/>
    </datasource>
    <groupDatasource id="personsDs"
                     class="com.company.demo.entity.Person"
                     view="_local">
        <query>
            <![CDATA[select e from demo$Person e]]>
        </query>
    </groupDatasource>
    <collectionDatasource id="allTagsDs"
                          class="com.company.demo.entity.Tag">
        <query>
            <![CDATA[select e from demo$Tag e]]>
        </query>
    </collectionDatasource>
</dsContext>
<twinColumn id="twinColumn"
            datasource="personDs"
            property="tags"
            caption="Tags"
            optionsDatasource="allTagsDs"/>

In the screen controller you can track the value changes and update the datasource:

public class PersonBrowse extends EntityCombinedScreen {
    @Inject
    private TwinColumn twinColumn;
    @Inject
    private CollectionDatasource<Tag, UUID> tagsDs;

    @Override
    public void ready() {
        twinColumn.addValueChangeListener(e -> {
            HashSet<Tag> selectedTags = e.getComponent().getValue();
            tagsDs.clear();
            for (Tag tag : selectedTags)
                tagsDs.addItem(tag);
        });
    }
}

I’ve attached a small sample project for your inspiration:
demo.zip (95.3 KB)

See more on setting initial values here: Setting TwinColumn default value - CUBA.Platform

1 Like

Thanks!

Worked like a charm. The trick was to use the nested datasource.