3.6.2.5. DsContext
|
Это устаревший API. Новый API, доступный начиная с v.7.0, описан в разделе Компоненты данных. |
Все созданные декларативно источники данных регистрируются в объекте DsContext экрана. Ссылку на DsContext можно получить методом getDsContext() контроллера экрана, либо инжекцией в поле класса.
DsContext решает следующие задачи:
-
Позволяет организовать зависимости между источниками данных, когда при навигации по одному источнику (т.е. при изменении "текущего" экземпляра методом
setItem()) обновляется связанный источник. Такие зависимости дают возможность в экранах легко организовывать master-detail связи между визуальными компонентами.Зависимости между источниками организуются с помощью параметров запросов с префиксом
ds$. -
Позволяет собрать все измененные экземпляры сущностей и отправить их на Middleware в одном вызове
DataManager.commit(), т.е. сохранить в базе данных в одной транзакции.В качестве примера предположим, что некоторый экран позволяет редактировать экземпляр сущности
Orderи коллекцию принадлежащих ему экземпляровOrderLine. ЭкземплярOrderнаходится вDatasource, коллекцияOrderLine- во вложенномCollectionDatasource, созданном по атрибутуOrder.lines. Допустим, пользователь изменил какой-то атрибутOrderи создал новый экземплярOrderLine. Тогда при коммите экрана в DataManager будут одновременно отправлены два экземпляра - измененныйOrderи новыйOrderLine. Далее, они вместе попадут в один персистентный контекст и при коммите транзакции сохранятся в БД. Это позволяет не использовать параметров каскадности на уровне ORM и избежать проблем, упомянутых в описании аннотации @OneToMany.В результате коммита
DsContextполучает от Middleware набор сохраненных экземпляров (в случае оптимистической блокировки у них, как минимум, увеличено значение атрибутаversion), и устанавливает эти экземпляры в источниках данных взамен устаревших. Это позволяет сразу после коммита работать со свежими экземплярами без необходимости лишнего обновления источников данных, связанного с запросами к Middleware и базе данных. -
Объявляет два слушателя:
BeforeCommitListenerиAfterCommitListener, позволяющие получать оповещения перед коммитом измененных экземпляров и после него. Перед коммитом можно дополнить коллекцию отправляемых в DataManager на Middleware экземпляров, тем самым обеспечив сохранение в той же транзакции произвольных сущностей. После коммита можно получить коллекцию вернувшихся изDataManagerсохраненных экземпляров.Данный механизм необходим, если некоторые сущности, с которыми работает экран, находятся не под управлением источников данных, а создаются и изменяются непосредственно в коде контроллера. Например, визуальный компонент FileUploadField после загрузки файла создает новый экземпляр сущности
FileDescriptor, который можно сохранить вместе с другими сущностями экрана именно таким способом - добавив вCommitContextв слушателеBeforeCommitListener.В следующем примере новый экземпляр
Customerбудет отправлен на Middleware и сохранен в БД вместе с остальными измененными сущностями экрана при его коммите:protected Customer customer; protected void createNewCustomer() { customer = metadata.create(Customer.class); customer.setName("John Doe"); } @Override public void init(Map<String, Object> params) { getDsContext().addBeforeCommitListener(context -> { if (customer != null) context.getCommitInstances().add(customer); } }