Применение изменений в ассоциированном Datasource

Document ассоциирован с Unit в отношении многие-ко-многим.
В экране редактирования Dcoument размещена стандартная таблица для добавления Unit:
image

Таблица editable = true, также как и колонка Condition.

Поскольку связь не ассоциация, изменения в этом поле таблицы не применяются для Unit. Хочу коммитить эти изменения в экране. Повесил на Datasource unitsDs слушатель addItemPropertyChangeListener. При отладке вижу, что листнер срабатывает и соответственно свойство в datasource было изменено.
В postCommit() хотел проверять были ли изменения в unitsDs и коммитить их.
Странность заключается в том, что unitsDs.isModified() возвращает false. Это ошибка?

1 симпатия

Привет!

Попробуй проверять в PreCommit.

preCommit() - шаблонный метод, вызываемый фреймворком в процессе коммита изменений, после того как валидация завершена успешно и перед отправкой данных на Middleware

PostCommit это уже после сохранения изменений, вот он в true.

postCommit() - шаблонный метод, вызываемый фреймворком на финальной стадии коммита изменений.

Посмотри диаграмму в доке.

Кирилл, пробовал до этого и перепроверил сейчас.
В preCommit unitsDs.isModified() также возвращает false.

Собери тестовый проект, выложи, давай посмотрим.

Создаем Entity1, создаем через кнопку Create в зависимом источнике Entity2, сохраняем Entity1.
Открываем Entity1, в таблице из выпадающего списка выбираем значение энумератора, сохраняем Entity1.
testNestedDatasource.zip (88,1 КБ)

Здравствуйте, @sergeevms

это действительно похоже на проблему. Ссылка на тикет в баг-трекере: YouTrack.

С наилучшими пожеланиями,
Даниил.

1 симпатия

Обходного решения не предложите, пока фиксится бага? Я так понимаю фикс не скоро, поскольку пойдет только в 6.9.

Обходное решение вы уже частично нашли - использовать PropertyChangeListener. При срабатывании поднимать флаг об изменённых данных и в preCommit'е сохранять изменения.

Даниил, позволю себе уточнить.

Просто записать в переменную класса, а потом проверять ее в preCommit и комитить DS? Так это не помогает. Видимо ds.commit() не отправляет изменений в БД, если isModified = false. Или есть способ указать, что ds изменился?

И позвольте вопрос не по теме. Как имея property (String), полученное в PropertyChangeListener (e.getProperty), получить field, для того, чтобы установить значение?

Вот более корректное решение вашей проблемы: на экране редактирования сущности Document надо заменить дочерний источник данных отдельно стоящим.

Пример. Меняем это:

<dsContext>
    <datasource id="barDs"
                class="com.company.app.entity.Bar"
                view="bar-view">
        <collectionDatasource id="foosDs"
                              property="foos"/>
    </datasource>
</dsContext>

На это:

<dsContext>
    <datasource id="barDs"
                class="com.company.app.entity.Bar"
                view="bar-view">
    </datasource>
    <collectionDatasource id="foosDs"
                          class="com.company.app.entity.Foo"
                          view="foo-view"
                          allowCommit="true"
                          >
        <query>
            select f from app$Foo f where f.id in (select foos.id from app$Bar bar join bar.foos foos where bar.id = :ds$barDs)
        </query>
    </collectionDatasource>
</dsContext>

Единственно, что придётся сделать дополнительно - это вручную обновлять коллекцию Unit'ов. Пример:

@Inject
private CollectionDatasource<Foo, UUID> foosDs;

@Override
public void init(Map<String, Object> params) {
    foosDs.addCollectionChangeListener(e ->
            getItem().setFoos(new ArrayList<>(foosDs.getItems())));
}

Отвечаю на второй вопрос. Для этого нужно воспользоваться методом setValueEx():

entity.setValueEx(property, value);

С наилучшими пожеланиями,
Даниил

2 симпатии

Даниил, премногоблагодарен.

Тут точно правильно? Я понимаю смысл запроса. Понимаю, как построить такой запрос в nativeQuery - соединение в нем будет из трех таблиц (поскольку многие-ко-многим). И совершенно не понял этой магии в jpa. Попробовал, как обезьянка, перенести, не получилось state() is invalid.
Может должно быть как-то так (хотя так тоже не получилось)?

select foos.id from app$Bar bar join app$Foo foos where bar.id = :ds$barDs

Не существует ли в IDEA какого-то инструмента для построения и выполнения jpql прежде чем запихивать его в код?

Михаил, привет!

Для

запуска произвольных JPQL запросов в контексте Middleware методами jpqlLoadList()

можно попробовать использовать JMX-bean

1 симпатия

Да, тут точно правильно.

Суть запроса такова: загрузить все id тех экземпляров сущности Foo (алиас foos), которые связаны с сущностью Bar, идентификатор которой совпадает с идентификатором сущности Bar установленной как item в источнике данных barDs.

К сожалению, такой инструмент мне неизвестен, однако несколько облегчить ситуацию может редактирование JPQL запроса в CUBA Studio, которая будет выполнять Hot-Deploy для нужного вам экрана.

1 симпатия

Спасибо, Кирилл. Очень мне помогло. Теперь я хотя бы вижу, что вот такой запрос выполняется корректно:

select e from wellsequpmentdb$Unit e where e.id in (select units.id from wellsequpmentdb$InstallDocument doc join doc.units units where doc.id = '6f618318-21c3-1cac-e77b-513e6eb06646')

Проблема возникает (ds is INVALID), когда я переношу это в контроллер экрана следующим образом:

select e from wellsequpmentdb$Unit e where e.id in (select units.id from wellsequpmentdb$InstallDocument doc join doc.units units where doc.id = :ds$installDocumentDs)

Источники объявлены как:

    <dsContext>
        <datasource id="installDocumentDs"
                    class="com.company.wellsequpmentdb.entity.InstallDocument"
                    view="installDocument-edit-screen">
        </datasource>
        <collectionDatasource id="unitsDss"
                              class="com.company.wellsequpmentdb.entity.Unit">
            <query>
                <![CDATA[select e from wellsequpmentdb$Unit e where e.id in (select units.id from wellsequpmentdb$InstallDocument doc join doc.units units where doc.id = :ds$installDocumentDs)]]>
            </query>
        </collectionDatasource>
    </dsContext>