5.4.2. Data Stores

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

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

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

Каждое CUBA-приложение имеет основное хранилище, которое содержит системные сущности и используется для входа пользователей в приложение. В данном руководстве под базой данных всегда имеется в виду основное хранилище, если явно не оговорено другое. Основное хранилище должно представлять собой реляционную БД, подключенную через источник данных JDBC. Источник данных основного хранилища находится в JNDI с именем, указанным в свойстве приложения cuba.dataSourceJndiName (по умолчанию jdbc/CubaDS).

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

  • cuba.dataSourceJndiName_{store_name} - JNDI-имя соответствующего источника данных JDBC.

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

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

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

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

cuba.additionalStores = db1, mem1
cuba.dataSourceJndiName_db1 = jdbc/db1
cuba.dbmsType_db1 = postgres
cuba.persistenceConfig_db1 = com/company/sample/db1-persistence.xml
cuba.storeImpl_mem1 = sample_InMemoryStore

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

Tip

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

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

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.

Tip

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