Добрый день!
У меня есть следующий дескриптор экрана с кастомным фильтром:
<view xmlns="http://jmix.io/schema/flowui/view"
title="msg://policyUiDtoListView.title"
focusComponent="policiesUiDtoesDataGrid">
<data>
<collection id="policiesUiDtoesDc"
class="ru.ctsg.damdbf.manager.ui.dto.policy.PolicyUiDto">
<fetchPlan extends="_base"/>
<loader id="policiesUiDtoesDl" readOnly="true"/>
</collection>
<instance id="policyUiDtoDc"
class="ru.ctsg.damdbf.manager.ui.dto.policy.PolicyUiDto">
<fetchPlan extends="_base">
<property name="conditionRequest"/>
<property name="actions"/>
</fetchPlan>
</instance>
</data>
<layout padding="false">
<details id="details" summaryText="msg://ru.ctsg.damdbf.manager.view.agent/filter" opened="true">
<formLayout id="formLayout">
<responsiveSteps>
<responsiveStep minWidth="0em" columns="3"/>
</responsiveSteps>
<multiSelectComboBox id="filterNameComboBox" property="name"
label="msg://ru.ctsg.damdbf.manager.ui.dto.policy/PolicyUiDto.name"
width="15em" classNames="filterBox"/>
<multiSelectComboBox id="filterStatusComboBox"
itemsEnum="ru.ctsg.damdbf.manager.core.enums.PolicyStatus"
label="msg://ru.ctsg.damdbf.manager.ui.dto.policy/PolicyUiDto.status" width="15em"
classNames="filterBox"/>
<multiSelectComboBox id="filterUserComboBox" property="user"
label="msg://ru.ctsg.damdbf.manager.ui.dto.policy/PolicyUiDto.user" width="15em"
classNames="filterBox"/>
<multiSelectComboBox id="filterDatabasesComboBox" property="databases"
label="msg://ru.ctsg.damdbf.manager.ui.dto.policy/PolicyUiDto.databases" width="15em"
classNames="filterBox"/>
<dateTimePicker id="filterCreatedAtFromDateTimePicker" property="createdAt"
label="msg://ru.ctsg.damdbf.manager.ui.dto.policy/PolicyUiDto.createdAtFromFilter"
width="15em" classNames="filterBox"/>
<dateTimePicker id="filterCreatedAtToDateTimePicker" property="createdAt"
label="msg://ru.ctsg.damdbf.manager.ui.dto.policy/PolicyUiDto.createdAtToFilter"
width="15em" classNames="filterBox"/>
<dateTimePicker id="filterUpdatedAtFromDateTimePicker" property="updatedAt"
label="msg://ru.ctsg.damdbf.manager.ui.dto.policy/PolicyUiDto.updatedAtFromFilter" width="15em"
classNames="filterBox"/>
<dateTimePicker id="filterUpdatedAtToDateTimePicker" property="updatedAt"
label="msg://ru.ctsg.damdbf.manager.ui.dto.policy/PolicyUiDto.updatedAtToFilter" width="15em"
classNames="filterBox"/>
<hbox classNames="hboxFilterButton" colspan="3">
<button id="refreshFilterBtn" action="policiesUiDtoesDataGrid.refresh" classNames="refreshFilterBtn"/>
<button id="clearFilterBtn" action="policiesUiDtoesDataGrid.clear" classNames="clearFilterBtn"/>
</hbox>
</formLayout>
</details>
<tabs id="tabs" width="100%">
<tab id="policiesDatabaseTab" label="msg://databaseApplicationTab"/>
<tab id="policiesApplicationTab" label="msg://policiesApplicationTab"/>
</tabs>
<hbox height="100%" width="100%">
<split id="splitPolicy" colspan="2" width="100%" splitterPosition="65">
<vbox id="listLayout" height="100%">
<hbox id="buttonsPanel" classNames="buttons-panel">
<button id="createBtn" action="policiesUiDtoesDataGrid.create"/>
<button id="editBtn" action="policiesUiDtoesDataGrid.edit"/>
<button id="removeBtn" action="policiesUiDtoesDataGrid.remove"/>
<dropdownButton id="dropdownButton" text="msg://dropdownButtonInPolicy" enabled="false">
<items>
<textItem id="textItemFirst" text="msg://allOnDatabase"/>
<textItem id="textItemSecond" text="msg://selectOnDatabase"/>
</items>
</dropdownButton>
</hbox>
<dataGrid id="policiesUiDtoesDataGrid"
width="100%"
minHeight="20em"
dataContainer="policiesUiDtoesDc"
columnReorderingAllowed="true">
<actions>
<action id="create" type="list_create"/>
<action id="edit" type="list_edit"/>
<action id="remove" type="list_remove"/>
<action id="refresh" type="list_refresh" text="msg://ru.ctsg.damdbf.manager.ui.action/Search"
icon="SEARCH"/>
<action id="clear" text="msg://ru.ctsg.damdbf.manager.ui.action/Clear" icon="MINUS_CIRCLE_O"/>
</actions>
<columns resizable="true">
<column key="icon" header="msg://policy/Status" sortable="false" autoWidth="true"/>
<column property="name"/>
<column property="user"/>
<column property="databases"/>
<column property="createdAt"/>
<column property="updatedAt"/>
</columns>
</dataGrid>
<hbox alignSelf="CENTER">
<simplePagination id="pagination" dataLoader="policiesUiDtoesDl"
itemsPerPageVisible="true"
itemsPerPageItems="10, 20, 50, 100" itemsPerPageDefaultValue="10"
alignSelf="CENTER"/>
</hbox>
</vbox>
<vbox id="detailsLayout" height="100%">
<formLayout id="form" dataContainer="policyUiDtoDc" classNames="formLayoutPolicyInfo">
<textArea id="conditionsField" label="msg://conditionLabel" height="300px"
readOnly="true"/>
<textArea id="actionsField" label="msg://actionsLabel" height="300px"
readOnly="true"/>
</formLayout>
</vbox>
</split>
</hbox>
</layout>
</view>
В контроллере экрана определен dlLoadDelegate
:
@Install(to = "policiesUiDtoesDl", target = Target.DATA_LOADER)
public List<PolicyUiDto> policiesDlLoadDelegate(final LoadContext<PolicyUiDto> loadContext) {
LoadContext.Query query = loadContext.getQuery();
if (query != null) {
int offset = query.getFirstResult();
int limit = query.getMaxResults();
Map<String, Object> conditionsMap = processConditions();
boolean hasNonNullValues = conditionsMap.values().stream().anyMatch(Objects::nonNull);
if (hasNonNullValues) {
return policiesUiService.getPolicies(offset, limit, isApplicationPolicy);
}
return policiesUiService.getPolicies(offset, limit, isApplicationPolicy);
} else {
return Collections.emptyList();
}
}
Я столкнулся с такой проблемой: мне нужно на основании значений в компонентах моего фильтра формировать sql-запрос и отправлять его в БД для фильтрации данных. Для других экранов, где в дескрипторе для loader
определен query
я вытаскиваю из компонентов данные, предварительно проверяя, что они не равны null
. Если не равны, то создаю PropertyConditon
, создаю LogicalCondtion
с AND
условием, складываю в loader
все получившиеся условия при помощи метода setCondition
, вызываю метод load
и все работает. В данном экране это работать не будет, т.к. я определяю свою логику загрузки данных для loader
.
Соответственно вопрос: я прохожусь по всем своим компонентам, получаю данные, если пользователь их указал и формирую Map<String, Objec>
, где в качестве ключа указано имя поля, а в качестве значения - лежит значение, полученное из компонента. Понятно, что данная Map
будет всегда разная (зависеть от того, сколько параметров пользователь выбрал в фильтрах). И на ее основе нужно формировать запрос к БД, который должен строиться динамически. Можно ли этого как-то добиться? Читал, что этого можно добиться через использование Spring Data Specification
и Criteria API
. Но пока в JMIX не получилось это реализовать.