Use attribute of inherited child in parent class screen

Hi

We have the superclass “Identity” and inherited children “Group” and “User”. In the browse screen for “Identity”, we would like to display both groups and users.

The instance name for “Identity” should be “[accountname] (User [surName] [preName])”, if the “Identity” is a user.
All our simple approaches failed - probably due to the fact that for the ORM, an “Identity” - Instance is just an Identity and does not know the childrens attributes.

Question:

  • Do you see a solution for this requirement?
  • A View can not be configured to contain attributes of inherited children - correct? In our case a view of Identity - entities can not contain the attributes User.surName and User.preName?

Cheers
Oliver

Hi.
“A View can not be configured to contain attributes of inherited children” - yes, you’re right.

Please check our guide demonstrates how to use entity inheritance.

Also, you can see the old sample project that demonstrates how to use entity inheritance too, but the project is implemented on the old platform version and uses legacy code.

Regards,
Natalia.

Hi Oliver,

Natalia is right, but you still can have all subclasses in a single browser with some manual coding.

First, create a database view that selects the superclass together with all subclasses. You can define it in 30.create-db.sql file to create automatically on database initialization:

create view DEMO_IDENTITY_VIEW as
    select i.*, u.SUR_NAME, u.PRE_NAME, g.GROUP_CODE
    from DEMO_IDENTITY i
        left join DEMO_USER u on u.ID = i.ID
        left join DEMO_GROUP g on g.ID = i.ID;

Then create an entity and map it to the database view:

@DbView
@Table(name = "DEMO_IDENTITY_VIEW")
@Entity(name = "demo_IdentityView")
public class IdentityView extends StandardEntity {
    private static final long serialVersionUID = -5860138124974857670L;

    @Column(name = "DTYPE")
    private String identityType; // this field helps to distinguish types

    @Column(name = "ACCOUNT_NAME")
    private String accountName;

    @Column(name = "SUR_NAME")
    private String surName;

    @Column(name = "PRE_NAME")
    private String preName;

    @Column(name = "GROUP_CODE")
    private String groupCode;

    // getters and setters
}

Create a browser screen for IdentityView entity and editor screens for concrete classes User and Group.

In the browser screen, create separate actions for creating Users and Groups:

<groupTable id="identityViewsTable" ...>
    <actions>
        <action id="createUser" type="create" caption="Create User"/>
        <action id="createGroup" type="create" caption="Create Group"/>
        ...
    </actions>
    <buttonsPanel id="buttonsPanel" ...>
        <button id="createUserBtn" action="identityViewsTable.createUser"/>
        <button id="createGroupBtn" action="identityViewsTable.createGroup"/>
        ...
    </buttonsPanel>

In the screen descriptor, override action handlers to dispatch to editor screens of concrete entities:

@UiController("demo_IdentityView.browse")
@UiDescriptor("identity-view-browse.xml")
@LookupComponent("identityViewsTable")
@LoadDataBeforeShow
public class IdentityViewBrowse extends StandardLookup<IdentityView> {

    @Inject
    private GroupTable<IdentityView> identityViewsTable;
    @Inject
    private ScreenBuilders screenBuilders;
    @Inject
    private DataManager dataManager;
    @Inject
    private CollectionLoader<IdentityView> identityViewsDl;

    @Subscribe("identityViewsTable.createUser")
    public void onIdentityViewsTableCreateUser(Action.ActionPerformedEvent event) {
        screenBuilders.editor(User.class, this)
                .withScreenClass(UserEdit.class)
                .newEntity(dataManager.create(User.class))
                .withAfterCloseListener(userEditAfterScreenCloseEvent -> refresh())
                .build()
                .show();
    }

    @Subscribe("identityViewsTable.createGroup")
    public void onIdentityViewsTableCreateGroup(Action.ActionPerformedEvent event) {
        screenBuilders.editor(Group.class, this)
                .withScreenClass(GroupEdit.class)
                .newEntity(dataManager.create(Group.class))
                .withAfterCloseListener(userEditAfterScreenCloseEvent -> refresh())
                .build()
                .show();
    }


    @SuppressWarnings("unchecked")
    @Subscribe("identityViewsTable.edit")
    public void onIdentityViewsTableEdit(Action.ActionPerformedEvent event) {
        IdentityView identityView = identityViewsTable.getSingleSelected();
        if (identityView == null)
            return;

        Identity identity;
        Class editorClass;
        if (identityView.getIdentityType().equals("demo_User")) {
            identity = dataManager.load(User.class).id(identityView.getId()).one();
            editorClass = UserEdit.class;
        } else {
            identity = dataManager.load(Group.class).id(identityView.getId()).one();
            editorClass = GroupEdit.class;
        }
        screenBuilders.editor(Identity.class, this)
                .withScreenClass(editorClass)
                .editEntity(identity)
                .withAfterCloseListener(afterScreenCloseEvent -> refresh())
                .build()
                .show();
    }

    @Subscribe("identityViewsTable.remove")
    public void onIdentityViewsTableRemove(Action.ActionPerformedEvent event) {
        IdentityView identityView = identityViewsTable.getSingleSelected();
        if (identityView == null)
            return;

        if (identityView.getIdentityType().equals("demo_User")) {
            dataManager.remove(Id.of(identityView.getId(), User.class));
        } else {
            dataManager.remove(Id.of(identityView.getId(), Group.class));
        }
        refresh();
    }

    private void refresh() {
        identityViewsDl.load();
    }
}

See the whole project attached:
demo.zip (86.9 KB)

2 Likes

Thank you both for your replies.

We’ll see if we change our requirement to be more in line with the standard functionality, or if we invest into “more manual code”.

1 Like