Datasource query filter

Доброго дня.
Правильно я понимаю, что такая функциональность в 7.0 отсутствует для новых источников?
https://doc.cuba-platform.com/manual-7.0/datasource_query_filter.html

Что-то предложите в замен?

Добавлю вопрос немного из другой темы, но тем не менее тоже ныне относящийся к legasy. @WindowParam теперь, как я понимаю, тоже устарел. Подскажите, а как в текущей парадигме решить следующую задачу?

Есть сущность А. В А есть атрибуты Country и Area (положим оба - pickerField). Необходимо, если выбрано значение в Country, при открытии лукапа Area отфильтровать все экземпляры в броуз-скрине по Country, а также при добавлении нового экземпляра Area устанавливать значение Country.

Для таких же, как я, которые в танке.
Первая часть задачи (передача параметра в lookup-screen) решается как-то так:

    @Subscribe("partNumberField.lookup")
    private void onPartNumberFieldLookup(Action.ActionPerformedEvent event) {
        screenBuilders.lookup(Part.class, this)
                .withField(partNumberField)
                .withOptions(new MapScreenOptions(ImmutableMap.of("partType", 20)))
                .build()
                .show();
    }

Получение переданного параметра в browse-screen:

    @Subscribe
    private void onInit(InitEvent event) {
        final ScreenOptions options = event.getOptions();
        if (options instanceof MapScreenOptions){
            final int partType = ((int) ((MapScreenOptions) options).getParams().get("partType"));
            });
        }
    }

Возможно есть варианты элегантней.

По второй части задачи пока понимания нет. Можно в лоб, как я понимаю, получить список и отфильтровать:

partsDc.getMutableItems().stream.filter(...)

Но, кмк, должен существовать вариант с фильтрацией перед получением данных, а не после такового.

1 симпатия

Уважаемые разработчики платформы, выражаю признательность за обновление документации, в лице @krivopustov.
https://doc.cuba-platform.com/manual-7.0-ru/gui_data_comp_param.html

“Старый” механизм был очень хорош тем, что можно было передать параметр в экран или не передавать его…
В описанном примере в экран в любом случае должна быть установлена страна, иначе будет выброшено исключение. Что делать, если при использовании в качестве справочника, я не хочу передавать страну, а если в качестве лукапа - передаю? Подменять запрос в Dl на лету?
Была мысль использовать 2 Dl в одном Dc:

        <collection id="districtsDc"
                    class="com.borets.wedb.entity.District"
                    view="district-view-with-country">
            <loader id="districtsDl">
                <query>
                    <![CDATA[select e from wedb$District e]]>
                </query>
            </loader>
            <loader id="districtCountryDl">
                <query>
                    <![CDATA[select e from wedb$District e where e.country = :country]]>
                </query>
            </loader>
        </collection>
    @Subscribe
    private void onBeforeShow(BeforeShowEvent event) {
        final DataLoader districtsFilteredByCountryDl = getScreenData().getLoader("districtCountryDl"); // При использовании инжекта, картина не изменяется.
        if (this.country == null)
            districtsDl.load();
        else {
            districtsFilteredByCountryDl.setParameter("country", this.country);
            districtsFilteredByCountryDl.load();
        }
    }

Хотя в xsd я не получаю никаких ошибок, но в рантайм я получаю следующее исключение:

IllegalArgumentException: Loader 'districtCountryDl' not found

Полагаю, дело в том, что в этом методе вы не предполагали множественность лоадеров в контейнере.

    protected void loadCollectionContainer(ScreenData screenData, Element element, @Nullable ScreenData hostScreenData) {
        String containerId = getRequiredAttr(element, "id");

        CollectionContainer<Entity> container;

        if (checkProvided(element, hostScreenData)) {
            //noinspection ConstantConditions
            container = hostScreenData.getContainer(containerId);
        } else {
            container = factory.createCollectionContainer(getEntityClass(element));
            loadView(element, getEntityClass(element), container);
        }

        screenData.registerContainer(containerId, container);

        Element loaderEl = element.element("loader");
        if (loaderEl != null) {
            loadCollectionLoader(screenData, loaderEl, container, hostScreenData);
        }

        for (Element collectionEl : element.elements()) {
            loadNestedContainer(screenData, collectionEl, container, hostScreenData);
        }
    }

Не знаю где это может выстрелить дальше, но может быть имеет смысл регистрировать все лоадеры в контейнере? Или вы предложите другое решение?
Выстрелит, как минимум, в методе loadAll

Очередной UPD:
Пока сделал вот так, но это как-то не очень…

    @Subscribe
    private void onBeforeShow(BeforeShowEvent event) {
        if (this.country != null) {
            districtsDl.setQuery(districtsDl.getQuery() + " where e.country = :country");
            districtsDl.setParameter("country", this.country);
        }
        districtsDl.load();
    }

Будет топик одного автора…
Может быть кому-то пригодится. Сделал так:

    @Install(to = "activitiesDl", target = Target.DATA_LOADER)
    private List<Activity> activitiesDlLoadDelegate(LoadContext<Activity> loadContext) {
        final LoadContext.Query query = loadContext.getQuery();
        final LogicalCondition condition = ((LogicalCondition) query.getCondition());
        if (well != null) condition.add(new JpqlCondition(null, "e.well = :well"));
        if (lookupTypes != null) condition.add(new JpqlCondition(null, "e.typeAct in :types"));
        query.setCondition(condition);
        query.setParameter("well", this.well);
        query.setParameter("types", this.lookupTypes);

        return dataManager.loadList(loadContext);
    }

Лукап-скрин вызывается так (впрочем, этот пример уже есть документации):

    @Subscribe("prevActivityField.lookup")
    private void onPrevActivityFieldLookup(Action.ActionPerformedEvent event) {
        final ActivityBrowse activityBrowse = screenBuilders.lookup(prevActivityField)
                .withScreenClass(ActivityBrowse.class)
                .build();
        activityBrowse.setWell(activity.getWell());
        activityBrowse.setLookupTypes(getLookupTypeSet());
        activityBrowse.show();
    }

Обратите внимание на https://doc.cuba-platform.com/manual-7.0/gui_data_loaders.html#gui_data_loader_query_conditions и на русском: https://doc.cuba-platform.com/manual-7.0-ru/gui_data_loaders.html

1 симпатия

Круто. Жаль этого не было, когда я читал этот раздел.

Андрей, прошу прощения. Но все же еще пару вопросов:

  1. зачем в пример мы удаляем параметр?
@Subscribe("nameFilterField")
private void onNameFilterFieldValueChange(HasValue.ValueChangeEvent<String> event) {
    if (event.getValue() != null) {
        customersDl.setParameter("name", "(?i)%" + event.getValue() + "%"); 
    } else {
        customersDl.removeParameter("name");
    }
    customersDl.load();
}
  1. По методологии. Рассмотрим пример с pickerField.
    https://doc.cuba-platform.com/manual-7.0-ru/gui_data_comp_param.html
    Это единственный вариант? Да, теперь используя ссылку из вашего предыдущего сообщения изменить условие у установить его в condition, но я по-прежнему должен отказаться в автозагрузки даталоадером данных и загружать данные самостоятельно (с использованием переменной класса)?
    Или все же есть возможность передать параметр в condition, описанный декларативно при переопределении метода lookup у pickerField?
  1. Параметр нужно удалять, поскольку Loader хранит значения параметров, и при очистке значения в фильтре нужно сбросить значение.
  2. В этом случае приходится отказываться от автоматической загрузки данных, и вручную загружать данные. Доработки в новых экранах велись к тому, чтобы сделать механизм загрузки данных менее автоматизированным. Это необходимо для того, чтобы разработчик понимал как загружаются данные и мог сам управлять загрузкой данных и их обновлением.

В документации еще недавно появился раздел с примесями: там есть пример как выстроить зависимости между загрузчиками данных в декларативном виде, а не в ручном. Для этого необходимо создать один класс, см https://doc.cuba-platform.com/manual-7.0-ru/screen_mixins.html#screen_mixin_declarative_loader_params

1 симпатия