3.4.2. Data Stores

Предпочтительный способ работы с данными в CUBA-приложениях - использование сущностей: либо декларативно в связанных с данными визуальных компонентах, либо программно через DataManager или EntityManager. Сущности отображаются на данные в хранилище, которое обычно представляет собой реляционную БД. Приложение может работать с несколькими хранилищами, так что его модель данных будет содержать сущности, отображаемые на данные из разных БД.

Некоторая сущность может принадлежать только одному хранилищу. Сущности из разных хранилищ можно отображать на одном экране UI, при этом DataManager обеспечивает их чтение и запись в соответствующее хранилище. В зависимости от типа сущности, DataManager выбирает зарегистрированное хранилище, представленное реализацией интерфейса DataStore, и делегирует ему загрузку или сохранение. При управлении транзакциями и работе с сущностями через EntityManager необходимо явно указывать, какое хранилище использовать. Подробнее см. методы интерфейса Persistence и параметры аннотации @Transactional.

Платформа содержит единственную реализацию интерфейса DataStore: RdbmsStore, предназначенную для работы с реляционными СУБД через слой ORM. Кроме того, в проекте приложения можно реализовать DataStore для интеграции, например, с нереляционной СУБД или внешней системой, имеющей REST интерфейс.

Каждое CUBA-приложение имеет основное хранилище, которое содержит системные сущности и используется для входа пользователей в приложение. В данном руководстве под базой данных всегда имеется в виду основное хранилище, если явно не оговорено другое. Основное хранилище должно представлять собой реляционную БД, подключенную через источник данных JDBC. Дополнительное хранилище может быть любой реализацией интерфейса DataStore.

CUBA Studio позволяет настраивать дополнительные хранилища, см. документацию. Studio автоматически создает все необходимые свойства приложения и поддерживает соответствующие файлы persistence.xml. После настройки хранилища его можно указать в поле Data store редактора сущности. Кроме того, хранилище можно выбрать при запуске мастера Generate Model для создания сущностей, отображенных на существующую схему БД.

Ниже приведена информация, которая может быть полезна при поиске проблем или если Studio не используется.

Имена дополнительных хранилищ указываются в свойстве приложения cuba.additionalStores. Если дополнительное хранилище является реляционной БД (RdbmsStore), необходимо указать для него следующие свойства приложения:

  • cuba.dbmsType_<store_name> - тип базы данных хранилища.

  • cuba.persistenceConfig_<store_name> - путь к файлу persistence.xml хранилища.

  • cuba.dataSource…​ - параметры подключения как описано в разделе Подключение к базам данных.

Если вы реализовали интерфейс DataStore в проекте, имя бина реализации должно быть указано в свойстве приложения cuba.storeImpl_<store_name>.

Предположим, что в вашем проекте два дополнительных хранилища: db1 (база данных PostgreSQL) and mem1 (некоторое in-memory хранилище, реализованное бином проекта). Тогда необходимо указать следующие свойства приложения в файле app.properties модуля core:

cuba.additionalStores = db1, mem1

# RdbmsStore for Postgres database with data source obtained from JNDI
cuba.dbmsType_db1 = postgres
cuba.persistenceConfig_db1 = com/company/sample/db1-persistence.xml
cuba.dataSourceJndiName_db1 = jdbc/db1

# Custom store
cuba.storeImpl_mem1 = sample_InMemoryStore

Свойства cuba.additionalStores и cuba.persistenceConfig_db1 необходимо также указать в файлах свойств всех используемых блоков приложения (web-app.properties, portal-app.properties, и т.д.).

Ссылки между сущностями из разных хранилищ

DataManager может автоматически поддерживать TO-ONE ссылки между сущностями из разных хранилищ, если они объявлены нужным образом. Например, рассмотрим случай, когда необходимо в сущности Order, находящейся в главном хранилище, иметь ссылку на сущность Customer из дополнительного хранилища. Необходимо сделать следующее:

  • В сущности Order определить атрибут типа, соответствующего идентификатору Customer. Атрибут должен быть аннотирован как @SystemLevel чтобы исключить его из различных списков, доступных пользователям, в частности из атрибутов в Filter:

    @SystemLevel
    @Column(name = "CUSTOMER_ID")
    private Long customerId;
  • В сущности Order определить неперсистентный атрибут-ссылку на Customer и указать атрибут customerId как "related":

    @Transient
    @MetaProperty(related = "customerId")
    private Customer customer;
  • Включите неперсистентный атрибут customer в нужные представления.

После этого, когда Order будет загружаться с представлением, включающим атрибут customer, DataManager будет автоматически загружать связанные экземпляры Customer из дополнительного хранилища. Загрузка коллекций оптимизирована по производительности: после загрузки списка заказов загрузка покупателей из доп. хранилища производится пакетами. Размер пакета определяется свойством приложения cuba.crossDataStoreReferenceLoadingBatchSize.

При коммите графа объектов, включающего Order со ссылкой на Customer, DataManager сохранит сущности через соответствующие имплементации DataStore, а затем сохранит идентификатор Customer в атрибуте customerId сущности Order.

Ссылки между сущностями из разных хранилищ поддерживаются компонентом Filter.

CUBA Studio автоматически поддерживает набор атрибутов для ссылок между сущностями из разных хранилищ, если в качестве ассоциации выбирается сущность из другого хранилища.