3.4.2. 数据存储
在 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}
- 相应 JDBC 数据源的 JNDI 名称。cuba.dbmsType_{store_name}
- 数据存储 DBMS 的类型。cuba.persistenceConfig_{store_name}
- 数据存储persistence.xml
文件的位置。
如果在项目中为附加存储实现了 DataStore
接口,需要在 cuba.storeImpl_{store_name}
应用程序属性中指定实现 bean 的名称。
例如,如果需要使用另外两个数据存储:db1
(PostgreSQL 数据库)和 mem1
(由某个项目 bean 实现的内存存储),请在 core 模块的 app.properties
中指定以下应用程序属性:
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
还应在所有应用程序 block 使用的属性文件(web-app.properties
、 portal-app.properties
等)中指定 cuba.additionalStores
和 cuba.persistenceConfig_db1
属性。
CUBA Studio 允许在 Project properties > Databases 标签页上设置其它数据存储。它会自动创建所有必须的应用程序属性和 JDBC 数据源,同时维护额外的 persistence.xml 文件。之后,可以在实体设计器的 Data store 字段中为实体选择数据存储。当使用 Generate model 向导为已有数据库创建实体时,也可以选择数据存储。 |
- 来自不同数据存储的实体之间的引用
如果正确定义了 DataManager,则可以自动维护来自不同数据存储的实体之间的 TO-ONE 引用。比如,在主数据存储中有Order
实体,在附加数据存储中有Customer
实体,并且希望在Order
中引用Customer
。可以这样做:
-
在Order
实体中,定义一个存储Customer
实体 ID 的属性。该属性应使用@SystemLevel
注解,以将其从用户可用的各种列表中排除,例如 Filter 中的可选属性:@SystemLevel
@Column(name = "CUSTOMER_ID")
private Long customerId;
-
在Order
实体中,定义对Customer
的非持久引用,并将 "related" 指定为customerId
:@Transient
@MetaProperty(related = "customerId")
private Customer customer;
-
在适当的视图中包含非持久化的customer
属性。
之后,当使用包含customer
属性的视图加载Order
时,DataManager
会自动从附加数据存储加载关联的Customer
。集合的加载针对性能进行了优化:在加载 Order 列表之后,从附加数据存储加载引用的 Customer 是分批完成的。每批加载的记录数由 cuba.crossDataStoreReferenceLoadingBatchSize 应用程序属性定义。
当提交引用了Customer
的Order
实体图时,DataManager
会通过相应的DataStore
进行数据保存,然后将 Customer 的 ID 保存在 Order 的customerId
属性中。
Filter 组件也支持跨数据存储引用。
在 Studio 中,如果使用了跨数据存储的实体引用属性,Studio 会自动维护这种引用关系。