Jmix 1.6 UI Filter - EntityPicker to String Field Property Multitenancy?

Hello,

I’m using the Multitenancy addon of JMIX and I’ve also extended the default TenantEntity (AffiliateCompanyEntity) to hold some project specific data related to tenants. I have defined a screen with a filter where users can search product objects by tenant (affiliate company) and the way the user selects tenants is through an entity lookup filter component:

<configurations>
   <configuration>
      <propertyFilter id="affiliateCompanyFilter" property="tenant" operation="EQUAL" caption="Search By Affiliate Company">
         <entityPicker metaClass="AffiliateCompanyEntity">
            <actions>
               <action id="entityLookup" type="entity_lookup">
                  <properties>
                     <property name="screenId" value="mten_Tenant.browse" />
                     <property name="openMode" value="DIALOG" />
                  </properties>
               </action>
            </actions>
         </entityPicker>
      </propertyFilter>
   </configuration>
</configurations>

The problem is that the tenant property on the target object is just the tenant id which is a string:

@TenantId
@Column(name = "TENANT")
private String tenant;

but the filter lookup component is of an entity type which causes this error:

Caused by: java.lang.IllegalArgumentException: You have attempted to set a value of type class c.c.c.b.entity.AffiliateCompanyEntity for parameter tenant daBRwodD with expected type of class java.lang.String from query string select e from ProductEntity e where e.tenant = :tenantdaBRwodD order by e.location.name desc.
	at org.eclipse.persistence.internal.jpa.QueryImpl.setParameterInternal(QueryImpl.java:946) ~[org.eclipse.persistence.jpa-2.7.9-7-jmix.jar:na]
	at org.eclipse.persistence.internal.jpa.EJBQueryImpl.setParameter(EJBQueryImpl.java:611) ~[org.eclipse.persistence.jpa-2.7.9-7-jmix.jar:na]

What are my options? Is there a way where the user still selects the Entity from the filter entity lookup component, but before it’s sent to the query I can use some value formatter to extract only the tenant property?

Hello!

Unfortunately generic filter doesn’t have value transformers or any similar functionality.

If you want to filter by custom value extracted from selected entity, the easiest way is to add an independent entity lookup component and filter using query conditions. E.g. for base Tenant entity and Users screen it will look the following way:

  1. Add condition to the data loader:
 <data ...>
        <collection id="usersDc" ... >
            <!--...-->
            <loader id="usersDl">
                <query>
                    <![CDATA[select e from User e order by e.username]]>
                     <condition>
                        <c:jpql>
                            <c:where>e.tenant like :tenantId</c:where>
                        </c:jpql>
                     </condition>
                </query>
            </loader>
        </collection>
    </data>
  1. Add entity picker:
<!--...-->
<layout>
    <!--...-->
        <entityPicker id="tenantPicker" metaClass="mten_Tenant" caption="Tenant">
            <actions>
                <action id="entityLookup" type="entity_lookup">
                    <properties>
                        <property name="screenId" value="mten_Tenant.browse"/>
                        <property name="openMode" value="DIALOG"/>
                    </properties>
                </action>
                <action id="clear" type="entity_clear"/>
            </actions>
        </entityPicker>
        <groupTable ... />
<!-- ...-->
  1. Set tenantId property in controller when selected entity is changed:
//...
public class UserBrowse extends StandardLookup<User> {
//...
    @Autowired
    private CollectionLoader<User> usersDl;

    @Subscribe("tenantPicker")
    public void onTenantPickerValueChange(final HasValue.ValueChangeEvent<Tenant> event) {
        usersDl.setParameter("tenantId", event.getValue() != null ? event.getValue().getTenantId() : null);
        usersDl.load();
    }
//...
}

Regards,
Dmitry