One-to-One Composition with a Single Editor on the user.edit screen with Extended user issue

Hello,

I am converting an old LightSwitch application over to Cuba Platform.

The lightswitch application has a seperate table called UsersSet which contained “profile” information about a user. I am using the example found here:

One-to-One Composition with a Single Editor

to add the logic to an extended user.edit screen.

I am receiving an error regarding initNewItem saying it is never used, also @Override reports “Method does not override method from its superclass

I am not sure what the issue is. I manually create/edit/associate from the user.edit screen, but since this is a one to one composition, I just want the UsersSet entity to be created when a new User is created.

I’m sure I am overlooking something, but if anyone could offer some insight it would be greatly appreciated.

user.edit Screen Controller below:

package com.company.ljtsiapp.web.screens;

import com.company.ljtsiapp.entity.UserExt;
import com.company.ljtsiapp.entity.UsersSet;
import com.haulmont.cuba.core.global.Metadata;
import com.haulmont.cuba.gui.app.security.user.edit.UserEditor;
import com.haulmont.cuba.gui.data.Datasource;

import javax.inject.Inject;
import java.util.Map;

public class ExtUserEditor extends UserEditor {

    @Inject
    private Metadata metadata;

    @Inject
    private Datasource<UserExt> userDs;

    @Inject
    private Datasource<UsersSet> userProfileDs;

    @Override
    public void init(Map<String, Object> params) {

    }

    //create new instance of UsersSet (UserProfile) Entity for one to one compo, edited on same screen.
    @Override
    protected void initNewItem(UserExt userExt) {
        userExt.setUserProfile(metadata.create(UsersSet.class));
    }

    @Override
    public boolean isModified() {
        // Prevents showing "do you want to save changes?" dialog window in case only the nested UserProfile is created while the Customer is not
        return userDs.isModified();
    }
    
}

image

This is the edit screen with the 1:1 composition on a single screen. editing values in nested datasource works, but only after the User Profile is manually made via the lookup component

UserExt (extended User) is the owning side, due to requirement not to change the schema of previously existing tables due to dozens of views and business logic based on existing schema.

image

Turns out I just forgot to set the user profile property in UserExt to composition. slaps forehead issue resolved.
yikes.

I spoke too soon, is it possible to initialize a new 1-1 composition when a new user is created?

Hi,

You can simply set an initial reference in initNewItem callback.

1 Like

I think I must be missing something obvious.

  • I have extended the sec.user with UserExt
  • UserExt contains only a 1:1 comopstion to UserProfile (UserExt is the owning side)
  • I have extended the user.edit screen

If I force the user to click to create a user profile from the extended user.edit screen that works fine, however I don’t want them even know it is happening. A new UserProfile should be created and associated with the user when they hit “create user.”

All logic below is on the UserExt edit screen controller (which extends, the user.edit screen controller)

image

package com.company.expensicon.web.screens;

import com.company.expensicon.entity.UserExt;
import com.company.expensicon.entity.UserProfile;
import com.haulmont.cuba.gui.app.security.user.edit.UserEditor;
import com.haulmont.cuba.gui.data.Datasource;
import com.haulmont.cuba.security.entity.User;

import javax.inject.Inject;
import java.util.Map;

public class ExtUserEditor extends UserEditor {

    @Inject
    private Datasource<UserExt> userDs;

    @Inject
    private Datasource<UserProfile> userProfileDs;
 
    protected void initNewItem(User user) {
        user.setTimeZoneAuto(true);
        user.setLanguage("en");
    }

    protected void initNewItem(UserExt userExt) {
        UserProfile up = metadata.create(UserProfile.class);
        userExt.setUserProfile(up);
    }

    @Override
    public void init(Map<String, Object> params) {
        super.init(params);
        userDs.addItemPropertyChangeListener(e -> syncValues());
    }


    public void syncValues() {
        String upFistName = userDs.getItem() != null ? userDs.getItem().getFirstName() : null;
        String upLastName = userDs.getItem() != null ? userDs.getItem().getLastName() : null;
        userProfileDs.getItem().setFirstName(upFistName);
        userProfileDs.getItem().setLastName(upLastName);

    }
}

You should add your logic into initNewItem(User user) method. According to Java method overriding rules: initNewItem(User) and initNewItem(UserExt) are different methods.

You may cast User in initNewItem(User) to UserExt if needed.

1 Like

That worked!

Thanks for your patience and help.

protected void initNewItem(User user) {
    user.setTimeZoneAuto(true);
    user.setLanguage("en");
    UserProfile up = metadata.create(UserProfile.class);
    ((UserExt) user).setUserProfile(up);
}