How to build a propertyFilter on a field joined from a different datastore

I have the following situation in Jmix (framework version 1.3.1, studio version 1.3.0.213):

I am using two datastores (one main, one additional). I have an entity “Task” which is from the main datastore, and an entity “Project” which is from the additional datastore. There is a relationship between them (a Project can have one or more Tasks). That is, on the Task entity there is this:

@SystemLevel
@Column(name = "PROJ_ID")
private Long proj_id;

@Transient
@JmixProperty
@DependsOnProperties({"proj_id"})
private Project project;

I am trying to build a Task browser (StandardLookup) with a propertyFilter on a field that is a property of Project; that is, something like this:

     <propertyFilter property="project.some_field" operation="CONTAINS" caption="..." dataLoader="tasksDl" align="BOTTOM_RIGHT" autoApply="true" />

The problem is that no approach I try works.

If I just do this:

         <loader dynamicAttributes="true" id="tasksDl">
             <query>
                 <![CDATA[select e from dsk_Task e]]>
             </query>
         </loader>

then I get an error message “The state field path ‘e.project.some_field’ cannot be resolved to a valid type.”

This seems to be because this query simply doesn’t load the “project” reference into the tasks it loads.

If I change it to this:

         <loader dynamicAttributes="true" id="tasksDl">
             <query>
                 <![CDATA[select e from dsk_Task e, dsk_Project p where e.proj_id = p.id]]>
             </query>
         </loader>

then the error message is different:

[26, 37] The abstract schema type ‘dsk_Project’ is unknown.
[58, 62] The state field path ‘p.id’ cannot be resolved to a valid type.

This seems to be because queries across datastores are not supported.

I also tried leaving the loader element empty and doing something like this in the controller:

@Install(to = "tasksDl", target = Target.DATA_LOADER)
private List<Task> tasksDlLoadDelegate(LoadContext<Task> loadContext) {
    List<Task> tasks = dataManager.load(Task.class).query(
            "select e from dsk_Task e"
    )
            .condition(loadContext.getQuery().getCondition())
            .list();
    for(Task task: tasks) {
        Optional<Project> project = dataManager.load(Project.class).query("select p from dsk_Project p where p.id = :id")
                .parameter("id", task.getProj_id())
                .optional();
        if (project.isPresent()) {
            task.setProject(project.get());
            task.setProj_id(project.get().getId());
        }
    }

    return tasks;
}

This again gives me the “cannot be resolved to a valid type” error above. This makes some sense: At the time the condition is applied (line starting with .condition) the project has not been loaded into the tasks yet, so there is nothing to filter. If I leave out the line starting with .condition, then I get no error, but no filter is applied either; also logical because there is no line that would apply the filter.

I would need to find a way to apply the condition I get from loadContext.getQuery().getCondition(), but only after the loop over the tasks has run, but cannot figure out how to do that.

Hi,

Can you send a sample project so i can debug it?

Regards,
Alex

You won’t be able to use the genericFilter or propertyFilter components for filtering by a property of entity from a different datastore. Because applying these filters boils down to creating a query over two data stores.

The only condition which an automatic filter can handle for cross-datastore references is by the referenced entity itself, like

<propertyFilter property="project" operation="CONTAINS" ...

because in this case the framework will create a query by ID of the Project entity which is stored in the Task entity itself.

If the expected number of Projects for a sought some_field is not very high (say up to few hundreds) you could create a custom filter which first finds all corresponding Projects and then loads Tasks by the IN condition with the list of Project IDs.

Regards,
Konstantin