5.2. 数据模型
在本节中,我们将介绍如何使用应用程序的数据模型。
5.2.1. 使用实体
创建新实体
在项目树中选择 Data Model 部分或它下面的包,然后从右键菜单中选择 New > Entity。
出现 New CUBA Entity 对话框。在 Entity name 字段中输入实体类的名称,选择实体及其 ID 的类型。
Studio 将创建实体类,根据实体类型的不同在
persistence.xml
或metadata.xml
中进行注册。创建的类会在源代码编辑界面中打开。
Studio 在实体源码编辑器底部显示 4 个标签页。一起组成实体可视化设计器:
Text 包含源码。
Designer 显示实体设计界面,可以使用图形界面配置实体及其属性,而不用编写 Java 代码。
- Indexes 展示索引,并且可以为选中的实体创建新索引。
DDL Preview 包含相应表及其参考约束的只读 DDL 代码。
Tip | 实体设计器只有激活 CUBA Studio 订阅才能使用。 |
创建实体属性
有多种方法可以向实体添加属性。
使用实体设计器的图形化界面:切换到 Designer 选项卡,单击 Attributes 表下方的 New 并填写 New Attribute 窗口中的必填字段。
Name 字段右边的地球仪按钮用于直接设置属性的用户友好名称。友好名称存储在
messages.properties
文件中,UI 组件默认使用这个文件来获取实体属性名称。如果为应用程序定义了多种语言,可以为所有语言指定本地化名称。使用从源码打开的独立窗口。在源码中将光标定位在最后一个字段下方,然后按下 Alt+Insert (Cmd+N)。在 Generate 菜单中,选择 Add Attribute。Studio 将显示 New Attribute 窗口,和从图形界面打开的一样。在代码编辑器的操作面板,也可以点击 Add attribute 按钮打开同样的窗口。
还可以手动编写属性字段,生成 getter 和 setter 方法,然后在 Generate 菜单中选择 JPA Annotations,这样可以使用默认参数添加 JPA 注解。
Studio 可以帮助将新增的属性添加到包含该实体的 UI 界面。打开 Text 标签页,然后点击源码编辑器顶部的 Add attributes to screens 操作。Studio 会搜索所有使用当前实体的界面,并分析哪些属性可以添加至这些界面的组件内。然后可以在对话框中选取需要的属性和界面组件:
还有一个类似功能的 Add to Screens 按钮,在实体的 Designer 标签页中 Attributes 表格的上方。
创建实例名称
可以用作另一个实体的引用属性的实体(例如 Customer
可以是 Order
的属性)需要一个 pattern 来生成实例的有意义的名称。此 pattern 由实体类上的 @NamePattern 注解定义。
如果您使用实体设计器编辑实体,可以有两种方式设置实体实例名称:
使用可视化构建器。可以点击 Instance name 字段的铅笔按钮:
自动模式。实体设计器检测到为实体添加下列属性之一时会自动生成实例名称:
name
、title
、caption
、label
、summary
、description
、firstName
、lastName
、middleName
。
实例名称还可以从实体的源代码创建,将光标定位在类名称上,按 Alt+Enter
(Option+Enter
)并选择 Add name pattern(仅当实体没有 @NamePattern
注解时才显示此项):
按 Enter 键,Studio 将显示实体的所有属性列表。选择一个或多个属性,然后按 Enter 键。Studio 将在实体类上生成 @NamePattern
。
为新属性创建消息
手动创建新的实体属性时,其名称会高亮突出显示,以提醒在相应的消息包中创建用户友好的属性名称:
在突出显示的属性上点击 Alt+Enter(Option+Enter),然后选择 Create message in the message bundle:
DDL 生成设置
Designer 标签页还可以配置 DDL 生成设置,能修改 Studio 为该实体生成数据库迁移脚本的方式。
移除实体
要移除实体,使用 Safe delete 选项查找并清理对实体的引用:
对实体的一些引用会被自动删除,比如在 persistence.xml
和 metadata.xml
文件中对实体的引用。如果存在对实体的引用,将会弹出一个对话框显示这些引用。 点击对话框上的 View Usages 按钮, 可在 Find 工具窗口中查看这些引用,这时可以根据情况点击 Cancel 或 Do Refactor 按钮。
5.2.2. 使用枚举
Studio 提供一组操作和可视化设计器帮助在应用程序中使用 枚举 。
枚举与实体一并在 CUBA 项目树的 Data Model 部分展示。
创建新的枚举
在项目树中选择 Data Model 或者其下面的一个包名,右键点击后选择 New > Enumeration 。
弹出 New CUBA Enumeration 对话框。在 Class 字段输入枚举类的名称,选择包名,Id 类型(推荐 String)。
Studio 将会创建枚举类,创建的类会在源码编辑器打开。编辑器的底部会显示两个标签页:
Text 包含源代码。
Designer 显示枚举设计器,这里可以使用图形界面配置枚举和值(常量),避免写 Java 代码。
使用 Values 表格和关联的按钮设置枚举值常量。
Name 列用于输入代码中使用的常量名称。这个名称可以后期修改而不影响数据库已经存在的数据。
Value 列用于输入枚举常量的 id。这是数据库保存的实际值。
地球按钮用于为选中的常量设置本地化名称(用户友好名称)。
设计器也提供将枚举的 Id type 从 String 修改为 Integer(或反过来)的功能。只需要打开枚举设计界面然后切换 Id type 的值。Studio 会自动在代码中对使用该枚举的地方做代码迁移。之后,您可以修改已有的枚举常量。注意,这种改动不会对数据库表格已存在的枚举值做改动,需要手动做数据迁移,比如可以通过一个数据库的更新脚本来实现。
5.2.3. 使用视图
视图 是对象关系图的一种描述,当实体从数据库加载时,用视图定义需要从数据库加载哪些属性、集合以及子实体。视图可以在界面描述中定义,也可以在单独的 views.xml
共享文件中定义,在后者定义的视图全局可用。
要为实体创建新的共享视图,请在项目树中选择实体,然后在右键菜单中点击 New > View。
会弹出视图编辑对话框,包含以下字段:
Entity name - 要创建视图的实体的名称。
Name - 新视图的名称。
Extends - 内置或自定义视图,新视图会扩展其属性。任何实体都有三种内置视图:
_local
包含实体的所有本地属性(不引用其它实体的属性),_minimal
包含名称模式中列出的属性,_base
包括所有本地非系统属性和由@NamePattern
定义的属性(实际上是_minimal
+_local
)。
Configuration file - 用于存储此视图的 视图配置文件。默认情况下,Studio 在
global
模块中生成一个views.xml
文件。
当前实体的完整属性列表显示在字段下方的树中。可以通过选中属性前面的复选框来选择要包含在视图中的属性。
如果视图继承另一个视图,则会选中所有继承的属性,并禁用相对应的复选框。
如果选择引用属性,则右侧面板中会显示以下属性:
Entity - 引用的实体名称。
View - 加载引用实体的可选视图。建议使用已命名视图而不是临时指定视图属性,因为这样可以更容易地维护复杂视图。此外,即使指定了视图名称,仍然可以通过选择属性树中的复选框来添加视图中未包含的属性。
Fetch - 用于引用属性的可选设置,指定如何从数据库中获取相关实体。有关详细信息,请参阅 文档。
单击 OK 关闭设计界面后,可以在实体下的项目树中找到新视图:
视图设计器
如果双击项目树中的视图项,Studio 将在代码编辑界面中打开 views.xml
并将光标定位在点击的视图定义处。代码编辑界面底部有两个选项卡:Text 和 Structure。Structure 标签显示此配置文件中定义的视图列表,并能可视化构建视图定义:
可以通过多种方式打开视图的图形设计界面:
在项目树中选择视图,然后单击 Edit View 右键菜单项。
将光标定位在配置文件代码中的视图元素上,按 Alt+Enter(Option+Enter),在弹出菜单中选择 Edit view,然后按 Enter 键。
切换到配置文件代码编辑界面的 Structure 选项卡,选择视图并点击 Edit 按钮。
使用视图设计器可以安全的重命名视图,能自动修改所有用到修改之前视图名称的地方。如需重命名视图,点击 Name 字段右侧的小铅笔按钮编辑即可。
Tip | 视图设计器需要激活 CUBA Studio 订阅才能使用。 |
手动编辑视图
也可以手动修改 views.xml
的源码来编辑视图定义。Studio 对视图配置文件的 XML 结构提供了完善的代码辅助支持。
当在 XML 中编辑视图定义时,使用 Ctrl+Space 启用属性名称自动完成功能:
需要注意高亮的属性,很可能他们不存在:
5.2.4. 数据库迁移
Studio 能够创建 DDL 脚本,以使数据库架构与项目的数据模型保持同步。生成的脚本可以从 Studio 直接执行,也可以由 Gradle 任务 执行,还可以在应用程序本身 启动时 执行。
可以为下列情况创建 DDL 脚本:
主数据存储
附加数据存储,需要使用 Create and Update 或 Update Only schema 管理模式。
有下列操作可以生成 DDL 脚本:
从主菜单选择 CUBA > Generate Database Scripts - 这里是为所有的数据存储生成脚本。
在项目树选择 Data Model 然后点击右键菜单的 Generate Database Scripts - 这里是为所有的数据存储生成脚本。
在 CUBA 项目树选择特定数据存储的节点,然后右键点击,菜单中选择 Generate Database Scripts - 这里只为选中的数据存储生成脚本。
然后 Studio 会打开 Database Scripts 窗口:
左侧的面板按数据存储对脚本做了分组。只有支持 DDL 脚本的数据存储才会显示。
数据库脚本有以下分类:
Updates
Updates 显示用来将数据库更新为数据模型当前状态的脚本。右侧的表格展示脚本列表,底部展示脚本内容。如果您的项目包含未执行的更新脚本,则会在左侧树高亮显示对应节点。更新脚本保存在 modules/core/db/update
或 modules/core/db/update_{additional_data_store_name}
目录。这些脚本具有自动生成的名称,通过前缀定义执行顺序。包含 DROP 语句的脚本以红色突出显示。
可以通过单击 按钮添加任意脚本,添加的脚本后续将与自动生成的脚本一起保存并执行。
单击 按钮可以编辑或完全删除新生成的脚本。
如果单击 (排除),这时会两个选项:
将脚本移动到手动执行的脚本目录:
modules/core/db/update-manually
或modules/core/db/update-manually_{additional_data_store_name}
。然后当运行 Update database 时,脚本不会自动被执行,但可以在需要时手动运行它。此选项对于用于删除先前重命名为*__UNUSED
的表或列的脚本非常有用。排除脚本:排除的脚本不会保存到
modules/core/db/update
目录中,而是记录在项目文件夹中的studio-intellij.xml
文件中。再次生成脚本时,Studio 将忽略与排除脚本相对应的更改。这样就允许数据库架构和实体模型之间存在差异。例如,可能希望在对应项目实体的一个表中添加数据库字段,但不将其映射到实体属性。当 Studio 生成了从数据库中删除该字段的脚本时,只需将其排除,Studio 将不再生成同样的脚本。
Init Tables
执行 Create Database 时,Init Tables 脚本会在 Init constraints 和 Init data 脚本之前执行,并创建所有的表。开发人员可以编辑脚本,但要需要保留分隔表的注释。该脚本保存在 10.create-db.sql
文件中。
Init Constraints
Init Constraints 脚本在 Init tables 脚本之后执行,创建完整性约束。开发人员可以编辑该脚本,但需要保留分隔表的注释。该脚本保存在 20.create-db.sql
文件中。
Init Data
Init Data 脚本允许插入额外的数据或数据模型中不存在的数据结构信息。在初始化结束时执行。该脚本保存在 30.create-db.sql
文件中。
如果项目包含应用程序组件(扩展),但是此组件不为当前数据库提供 DDL 脚本,Studio 会为组件生成脚本,并在 Init {component} tables 和 Init {component} constraints 部分显示。脚本分别保存在 01.{component}-create-db.sql
和 02.{component}-create-db.sql
文件中。
单击 Save and close 以保存所有生成的脚本。可以在 Project > Data Stores > Main Data Store 项目树部分中找到脚本。
要运行更新脚本,先停止应用程序服务器(如果在运行),然后从 CUBA 主菜单执行 Update Database 或 Update All Databases。如果只想更新一个数据存储,可以在 CUBA 项目树选中该存储节点,然后在右键菜单中选择 Update Database。
如果要使用初始化脚本从头开始重新创建数据库,请执行 Create Database 或 Create All Databases。如果只想重新创建一个数据存储,可以在 CUBA 项目树选中该存储节点,然后在右键菜单中选择 Create Database。
实体 DDL 脚本生成配置
可以在实体级别自定义 Studio 数据库迁移脚本的生成行为。实体设计器 的 Designer 标签页能配置当前实体的 DDL generation settings :
DB script generation mode - 选择合适的模式:
CREATE_AND_DROP - 默认模式。当生成 DDL 脚本时,Studio 可以在数据库创建表、列以及约束,并且可以在列或约束对应的数据模型属性不存在时 drop 掉列或约束。可以根据数据模型创建 init 和 update 脚本。
CREATE_ONLY - 在生成 update 脚本时,Studio 不会尝试 drop 列或约束。可以根据数据模型创建 Init 脚本。
DISABLED - Studio 不为该实体创建任何 init 和 update 脚本。
Unmapped columns - 一组只在数据库存在的列而没有对应的实体属性。Studio 不会尝试 drop 掉这些列。
Unmapped constraints - 一组只在数据库存在的约束而没有对应的实体属性。Studio 不会尝试在 update 脚本中 drop 掉这些约束。
这些设置也可以在源码手动配置,参阅 com.haulmont.cuba.core.global.DdlGeneration
注解(最低要求平台版本:7.1.6 或 7.2.2)。
5.2.5. 生成数据模型
Studio 允许为现有数据库创建数据模型和标准 UI 界面。单击 CUBA > Advanced > Generate Model 主菜单项或在项目树中选择 Project > Data Stores,然后在右键菜单中点击 Generate Model。如果有多个数据存储,Studio 会显示一个对话框,可以选择其一。
然后 Studio 打开 Generate Model from Database 向导。
步骤 1
这是模型生成向导的第一步。
可选步骤:单击 以设置创建的新实体的 Java 包位置以及实体的系统属性与数据库列的默认映射。
例如,如果数据库中的所有或大多数表包含 Modified
和 ModifiedBy
列,则可以将它们映射到被创建的实体的 Updatable.updateTs
和 Updatable.updatedBy
属性。在这种情况下,无需为每个表单独映射它们。
使用 Exclude columns from mapping 列表可以为所有表设置不需要映射到属性的列。
向导中会列出在项目数据模型中没有对应实体的表。可以使用上面的过滤器字段按名称查找表。
选择要映射到数据模型的表。某些表通过外键依赖于其它表,因此当选择这些表时,它所依赖的所有表也将被选中。如果取消选择一个表,则也会取消选择所有依赖它的表。
可以通过单击右侧的复选框来选择或取消选择所有可用表。
单击 Next。
步骤 2
在此步骤中,可以查看和编辑为所选表的自动生成的映射。
Status 列描述自动映射的结果:
OK - 自动映射成功,所有列都映射到新实体。
Join table - 识别出实体之间的关联,会被映射为多对多关系的连接表。
There are unmapped columns - 某些列无法映射到新实体。
New PK will be created - 该表没有主键。将创建一个新的 UUID 类型的主键。
Composite PK will be replaced - 该表具有复合主键,但没有其它表引用它。复合主键将被替换为 UUID 类型的主键。
Composite PK referenced by other tables - 该表有一个复合主键,一些表引用它。Studio 无法映射此类表。
Unsupported PK type - 该表具有不支持的主键类型。Studio 无法映射此类表。
Choose primary key for DB view - 它是一个数据库视图,应该选择适合作为实体标识符的一列或一组列。在这种情况下,单击 Choose PK 按钮并选择主键的列。
按钮允许重新运行所选表的自动映射。例如,可以切换到数据库 SQL 工具,对数据库架构进行一些更改,然后返回到向导并再次执行映射过程。
按钮打开一个包含映射详细信息的对话框窗口。在这里,可以更改实体名称和实体类要实现的系统接口。根据实现接口的不同,为了兼容 CUBA 的实体,会影响数据库列的创建数量。
当选中的是数据库视图并且需要选择用于实体标识符的列时,将显示 Choose PK 按钮而不是 Edit mapping。
通过单击 Back,可以返回到上一步以选择或取消选择表。
单击 Next 转到下一步。
步骤 3
在此步骤中,可以指定应为新实体创建哪些 UI 界面。
如果取消选中 Create standard screen 复选框,Studio 将不会为新实体生成 UI。
使用 In module 、Package 和 Menu 字段指定界面源代码的位置以及在主菜单中它们的显示位置。
使用 Standard screens 列中的下拉列表选择要生成的界面类型。
可以安全地跳过此步骤,并在完成模型生成过程后为实体生成 UI 界面。
单击 Next 转到下一步。
步骤 4
这是模型生成向导的最后一步。
Import scripts 表包含将在数据库上执行的脚本列表,查看这些脚本,以确认其符合要创建的实体。
在此之前,项目中不会创建任何内容,甚至也不会保存到磁盘中。Studio 实际上只会在点击 Run all scripts 或 Run script 时生成实体和界面并保存脚本。
可以在此页面上查看和编辑脚本,然后运行它们,或者仅保存脚本,稍后通过数据库管理工具来运行。导入脚本保存在 modules/core/db/import
目录中。
5.2.6. 集成自定义数据库
如 文档 中所述,框架允许使用 EclipseLink ORM 支持的任何 DBMS 作为项目数据库。Studio 可以帮助创建此类集成所需的文件。
在菜单中选择 CUBA > Advanced > Define Custom Database。
在打开的窗口中可以设置新自定义数据库的属性。根据这些属性,Studio 会针对数据库生成设计时和运行时的支撑代码。
DB type id - 用于
cuba.dbmsType
应用程序属性的数据库类型标识符。DB type name - 要在 Studio 中显示的数据库类型的用户友好名称。
单击 OK 后,Studio 会在 com.haulmont.cuba.core.sys.persistence
中生成 Java 类,并在项目的 com.haulmont.studio.db.{db_id}
包中生成 Groovy 类。自动生成的示例实现适用于 Microsoft SQLServer 数据库,需要适当地对其进行一些修改。
首先,修改 com.haulmont.studio.db.{db_id}.{db_id}DbProperties
类。当此类适配了新的数据库时,将能够在 Studio 中将项目切换到此数据库。重新打开项目在数据库类型下拉列表中查看新数据库。
要在运行时连接到新数据库,请修改 com.haulmont.cuba.core.sys.persistence
包的 {db_id}DbmsFeatures
和 {db_id}DbTypeConverter
类。{db_id}SequenceSupport
类仅用于生成整数标识符和唯一编号。
最后,修改 com.haulmont.studio.db.{db_id}.{db_id}DdlGenerator
类,以便在需要时可以由 Studio 正确生成 init 和 update 数据库脚本。如果不需要为此数据库生成 DDL 脚本,可跳过此步骤。
为主数据存储初始化数据脚本
如果将自定义数据库用作主数据存储,则在生成数据库脚本时,Studio 将为所有应用程序组件(包括 CUBA)创建 init 脚本。这些脚本不包含一些必须的初始化数据,因此必须将以下内容添加到项目的 Init data 脚本中(30.create-db.sql
),事实上,对于版本 7.2.0
:
insert into SEC_GROUP (ID, CREATE_TS, VERSION, NAME, PARENT_ID)
values ('0fa2b1a5-1d68-4d69-9fbd-dff348347f93', now(), 0, 'Company', null)^
insert into SEC_USER (ID, CREATE_TS, VERSION, LOGIN, LOGIN_LC, PASSWORD, PASSWORD_ENCRYPTION, NAME, GROUP_ID, ACTIVE)
values ('60885987-1b61-4247-94c7-dff348347f93', now(), 0, 'admin', 'admin',
'$2a$10$vQx8b8B7jzZ0rQmtuK4YDOKp7nkmUCFjPx6DMT.voPtetNHFOsaOu', 'bcrypt',
'Administrator', '0fa2b1a5-1d68-4d69-9fbd-dff348347f93', true)^
insert into SEC_USER (ID, CREATE_TS, VERSION, LOGIN, LOGIN_LC, PASSWORD, NAME, GROUP_ID, ACTIVE)
values ('a405db59-e674-4f63-8afe-269dda788fe8', now(), 0, 'anonymous', 'anonymous', null,
'Anonymous', '0fa2b1a5-1d68-4d69-9fbd-dff348347f93', true)^
insert into SEC_USER_ROLE (ID, CREATE_TS, VERSION, USER_ID, ROLE_NAME)
values ('6736effb-9dfc-4430-973a-69868606b09c', current_timestamp, 0, '60885987-1b61-4247-94c7-dff348347f93', 'system-full-access')^
添加 JDBC 驱动
当生成数据库迁移脚本时,Studio 需要对应数据库的 JDBC 驱动。使用自定义数据库,需要手动下载驱动文件并放置于 {USER_HOME}/.haulmont/studio/lib
目录(比如 windows 上:C:\Users\{username}\.haulmont\studio\lib
)。
在文件夹添加完驱动之后,别忘做下面几步:
重启 IDE。
停止 Gradle daemon(在终端执行
gradlew --stop
)。
集成 Firebird 数据库示例
集成自定义数据库(Firebird)至 CUBA 和 Studio 的示例可以在这里找到: https://github.com/cuba-labs/firebird-sample 。这个例子也可以作为扩展插件添加至您的项目以支持 Firebird 数据库。