5.2. 数据模型

在本节中,我们将介绍如何使用应用程序的数据模型。

5.2.1. 使用实体

创建新实体

  1. 在项目树中选择 Data Model 部分或它下面的包,然后从右键菜单中选择 New > Entity

  2. 出现 New CUBA Entity 对话框。在 Entity name 字段中输入实体类的名称,选择实体及其 ID 的类型。

  3. Studio 将创建实体类,根据实体类型的不同在 persistence.xmlmetadata.xml 中进行注册。创建的类会在源代码编辑界面中打开。编辑界面底部会显示三个选项卡:

    • Text 包含源码。

    • Designer 显示实体设计界面,可以使用图形界面配置实体及其属性,而不用编写 Java 代码。

    • DDL Preview 包含相应表及其参考约束的只读 DDL 代码。

创建实体属性

有多种方法可以向实体添加属性。

  • 使用实体设计器的图形化界面:切换到 Designer 选项卡,单击 Attributes 表下方的 New 并填写 New Attribute 窗口中的必填字段。

    Name 字段右边的地球仪按钮用于直接设置属性的用户友好名称。友好名称存储在 messages.properties 文件中,UI 组件默认使用这个文件来获取实体属性名称。如果为应用程序定义了多种语言,可以为所有语言指定本地化名称。

    attribute l10n

  • 使用从源码打开的独立窗口。在源码中将光标定位在最后一个字段下方,然后按下 Alt+Insert (Cmd+N)。在 Generate 菜单中,选择 Add Attribute。Studio 将显示 New Attribute 窗口,和从图形界面打开的一样。在代码编辑器的操作面板,也可以点击 Add attribute 按钮打开同样的窗口。

    new attribute 2

  • 还可以手动编写属性字段,生成 getter 和 setter 方法,然后在 Generate 菜单中选择 JPA Annotations,这样可以使用默认参数添加 JPA 注解。

Studio 可以帮助将新增的属性添加到为此实体创建的 UI 界面。将光标定位到包含该属性的行,然后按 Alt+Enter(Option + Enter)或单击灯泡图标并选择 Add entity attribute to screens

add attribute to screens

按 Enter 键,Studio 将打开一个对话框,其中包含使用了被编辑实体的界面列表。可以选择一个界面,Studio 会将该属性添加到此界面的相应 UI 组件中,例如添加到表格或表单中。

创建实例名称

可以用作另一个实体的引用属性的实体(例如 Customer 可以是 Order 的属性)需要一个模式(pattern)来生成实例的有意义的名称。此模式(pattern)由实体类上的 @NamePattern 注解定义。将光标定位在类名称上,即可在 Studio 中创建实体的名称模式,按 Alt+Enter(Option+Enter)并选择 Add name pattern(仅当实体没有 @NamePattern 注解时才显示此项):

create name pattern

按 Enter 键,Studio 将显示实体的所有属性列表。选择一个或多个属性,然后按 Enter 键。Studio 将在实体类上生成 @NamePattern

为新属性创建消息

手动创建新的实体属性时,其名称会高亮突出显示,以提醒在相应的消息包中创建用户友好的属性名称:

create message 1

在突出显示的属性上点击 Alt+Enter(Option+Enter),然后选择 Create message in the message bundle

create message

移除实体

要移除实体,使用 Safe delete 选项查找并清理对实体的引用:

remove entity

对实体的一些引用会被自动删除,比如在 persistence.xmlmetadata.xml 文件中对实体的引用。如果存在对实体的引用,将会弹出一个对话框显示这些引用。 点击对话框上的 View Usages 按钮, 可在 Find 工具窗口中查看这些引用,这时可以根据情况点击 CancelDo Refactor 按钮。

5.2.2. 使用枚举

Studio 提供一组操作和可视化设计器帮助在应用程序中使用 枚举

枚举与实体一并在 CUBA 项目树的 Data Model 部分展示。

创建新的枚举

  1. 在项目树中选择 Data Model 或者其下面的一个包名,右键点击后选择 New > Enumeration

  2. 弹出 New CUBA Enumeration 对话框。在 Class 字段输入枚举类的名称,选择包名,Id 类型(推荐 String)。

create enum

  1. Studio 将会创建枚举类,创建的类会在源码编辑器打开。编辑器的底部会显示两个标签页:

    • Text 包含源代码。

    • Designer 显示枚举设计器,这里可以使用图形界面配置枚举和值(常量),避免写 Java 代码。

enum designer

使用 Values 表格和关联的按钮设置枚举值常量。

  • Name 列用于输入代码中使用的常量名称。这个名称可以后期修改而不影响数据库已经存在的数据。

  • Value 列用于输入枚举常量的 id。这是数据库保存的实际值。

  • 地球按钮用于为选中的常量设置本地化名称(用户友好名称)。

设计器也提供将枚举的 Id type 从 String 修改为 Integer(或反过来)的功能。只需要打开枚举设计界面然后切换 Id type 的值。Studio 会自动在代码中对使用该枚举的地方做代码迁移。之后,您可以修改已有的枚举常量。注意,这种改动不会对数据库表格已存在的枚举值做改动,需要手动做数据迁移,比如可以通过一个数据库的更新脚本来实现。

5.2.3. 使用视图

要为实体创建新的 视图,请在项目树中选择实体,然后在右键菜单中点击 New > View

create view

视图设计界面会被打开。它包含以下字段:

  • Entity name - 要创建视图的实体的名称。

  • Name - 新视图的名称。

  • Extends - 内置或自定义视图,新视图会扩展其属性。任何实体都有三种内置视图:

    • _local 包含实体的所有本地属性(不引用其它实体的属性),

    • _minimal 包含名称模式中列出的属性,

    • _base 包括所有本地非系统属性和由 @NamePattern 定义的属性(实际上是 _minimal +_local)。

  • Configuration file - 用于存储此视图的 视图配置文件。默认情况下,Studio 在 global 模块中生成一个 views.xml 文件。

当前实体的完整属性列表显示在字段下方的树中。可以通过选中属性前面的复选框来选择要包含在视图中的属性。

如果视图继承另一个视图,则会选中所有继承的属性,并禁用相对应的复选框。

如果选择引用属性,则右侧面板中会显示以下属性:

  • Entity - 引用的实体名称。

  • View - 加载引用实体的可选视图。建议使用已命名视图而不是临时指定视图属性,因为这样可以更容易地维护复杂视图。此外,即使指定了视图名称,仍然可以通过选择属性树中的复选框来添加视图中未包含的属性。

  • Fetch - 用于引用属性的可选设置,指定如何从数据库中获取相关实体。有关详细信息,请参阅 文档

单击 OK 关闭设计界面后,可以在实体下的项目树中找到新视图:

create view 2

如果双击项目树中的视图项,Studio 将在代码编辑界面中打开 views.xml 并将光标定位在视图定义上。代码编辑界面底部有两个选项卡:TextStructure。后者显示此配置文件中定义的视图列表。

在 XML 中编辑视图定义时,使用 Ctrl+Space 自动完成属性名称:

view edit 1

要留意高亮突出显示的属性,它们很有可能不存在:

view edit 2

可以通过多种方式打开视图的图形设计界面:

  • 在项目树中选择视图,然后单击 Edit View 右键菜单项。

  • 将光标定位在配置文件代码中的视图元素上,按 Alt+Enter(Option+Enter),在弹出菜单中选择 Edit view,然后按 Enter 键。

  • 切换到配置文件代码编辑界面的 Structure 选项卡,选择视图并点击 Edit 按钮。

5.2.4. 数据库迁移

Studio 能够创建 DDL 脚本,以使数据库架构与项目的数据模型保持同步。生成的脚本可以从 Studio 直接执行,也可以由 Gradle 任务 执行,还可以在应用程序本身 启动时 执行。

要生成 DDL 脚本,请在主菜单中单击 CUBA > Generate Database Scripts,或在项目树中选择 Data Model,然后在右键菜单中单击 Generate Database Scripts

Studio 将打开 Database Scripts 窗口,窗口上有以下选项卡:

Updates

Updates 选项卡上显示出用来将数据库更新为数据模型当前状态的脚本。更新脚本保存在 modules/core/db/update 目录。这些脚本具有自动生成的名称,通过前缀定义执行顺序。包含 DROP 语句的脚本以红色突出显示。

可以通过单击 Create 按钮添加任意脚本,添加的脚本后续将与自动生成的脚本一起保存并执行。

单击 Remove 按钮可以编辑或完全删除新生成的脚本。

如果单击 Exclude selected(排除),这时会两个选项:

  • 将脚本移动到手动执行的脚本目录:modules/core/db/update-manually。然后当运行 Update database 时,脚本不会自动被执行,但可以在需要时手动运行它。此选项对于用于删除先前重命名为 *__UNUSED 的表或列的脚本非常有用。

  • 排除脚本:排除的脚本不会保存到 modules/core/db/update 目录中,而是记录在项目文件夹中的 studio-intellij.xml 文件中。再次生成脚本时,Studio 将忽略与排除脚本相对应的更改。这样就允许数据库架构和实体模型之间存在差异。

    例如,可能希望在对应项目实体的一个表中添加数据库字段,但不将其映射到实体属性。当 Studio 生成了从数据库中删除该字段的脚本时,只需将其排除,Studio 将不再生成同样的脚本。

Init Tables

执行 Create Database 时,Init Tables 脚本会在 Init constraintsInit 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} tablesInit {component} constraints 选项卡中显示。脚本分别保存在 01.{component}-create-db.sql02.{component}-create-db.sql 文件中。

单击 Save and close 以保存所有生成的脚本。可以在 Project > Data Stores > Main Data Store 项目树部分中找到脚本。

要运行更新脚本,先停止应用程序服务器(如果在运行),然后从 CUBA 主菜单执行 Update Database。如果要使用初始化脚本从头开始重新创建数据库,请执行 Create Database

5.2.5. 生成数据模型

Studio 允许为现有数据库创建数据模型和标准 UI 界面。单击 CUBA > Advanced > Generate Model 主菜单项或在项目树中选择 Project > Data Stores,然后在右键菜单中点击 Generate Model。如果有多个数据存储,Studio 会显示一个对话框,可以选择其一。

然后 Studio 打开 Generate Model from Database 向导。

步骤 1

这是模型生成向导的第一步。

generate model step1

可选步骤:单击 Settings 以设置创建的新实体的 Java 包位置以及实体的系统属性与数据库列的默认映射。

例如,如果数据库中的所有或大多数表包含 ModifiedModifiedBy 列,则可以将它们映射到被创建的实体的 Updatable.updateTsUpdatable.updatedBy 属性。在这种情况下,无需为每个表单独映射它们。

使用 Exclude columns from mapping 列表可以为所有表设置不需要映射到属性的列。

向导中会列出在项目数据模型中没有对应实体的表。可以使用上面的过滤器字段按名称查找表。

选择要映射到数据模型的表。某些表通过外键依赖于其它表,因此当选择这些表时,它所依赖的所有表也将被选中。如果取消选择一个表,则也会取消选择所有依赖它的表。

可以通过单击右侧的复选框来选择或取消选择所有可用表。

单击 Next

步骤 2

在此步骤中,可以查看和编辑为所选表的自动生成的映射。

generate model step2

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 按钮并选择主键的列。

Refresh mapping 按钮允许重新运行所选表的自动映射。例如,可以切换到数据库 SQL 工具,对数据库架构进行一些更改,然后返回到向导并再次执行映射过程。

Edit mapping 按钮打开一个包含映射详细信息的对话框窗口。在这里,可以更改实体名称和实体类要实现的系统接口。根据实现接口的不同,为了兼容 CUBA 的实体,会影响数据库列的创建数量。

generate model step2 2

当选中的是数据库视图并且需要选择用于实体标识符的列时,将显示 Choose PK 按钮而不是 Edit mapping

通过单击 Back,可以返回到上一步以选择或取消选择表。

单击 Next 转到下一步。

步骤 3

在此步骤中,可以指定应为新实体创建哪些 UI 界面。

generate model step3

如果取消选中 Create standard screen 复选框,Studio 将不会为新实体生成 UI。

使用 In modulePackageMenu 字段指定界面源代码的位置以及在主菜单中它们的显示位置。

使用 Standard screens 列中的下拉列表选择要生成的界面类型。

可以安全地跳过此步骤,并在完成模型生成过程后为实体生成 UI 界面。

单击 Next 转到下一步。

步骤 4

这是模型生成向导的最后一步。

Import scripts 表包含将在数据库上执行的脚本列表,查看这些脚本,以确认其符合要创建的实体。

在此之前,项目中不会创建任何内容,甚至也不会保存到磁盘中。Studio 实际上只会在点击 Run all scriptsRun 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 正确生成 initupdate 数据库脚本。如果不需要为此数据库生成 DDL 脚本,可跳过此步骤。

如果将自定义数据库用作主数据存储,则在生成数据库脚本时,Studio 将为所有应用程序组件(包括 CUBA)创建 init 脚本。这些脚本不包含一些必须的初始化数据,因此必须将以下内容添加到项目的 Init data 脚本中(30.create-db.sql):

  1. insert into SEC_GROUP (ID, CREATE_TS, VERSION, NAME, PARENT_ID)
  2. values ('0fa2b1a5-1d68-4d69-9fbd-dff348347f93', current_timestamp, 0, 'Company', null)^
  3. insert into SEC_USER (ID, CREATE_TS, VERSION, LOGIN, LOGIN_LC, PASSWORD, NAME, GROUP_ID, ACTIVE)
  4. values ('60885987-1b61-4247-94c7-dff348347f93', current_timestamp, 0, 'admin', 'admin',
  5. 'cc2229d1b8a052423d9e1c9ef0113b850086586a',
  6. 'Administrator', '0fa2b1a5-1d68-4d69-9fbd-dff348347f93', 1)^
  7. insert into SEC_USER (ID, CREATE_TS, VERSION, LOGIN, LOGIN_LC, PASSWORD, NAME, GROUP_ID, ACTIVE)
  8. values ('a405db59-e674-4f63-8afe-269dda788fe8', current_timestamp, 0, 'anonymous', 'anonymous', null,
  9. 'Anonymous', '0fa2b1a5-1d68-4d69-9fbd-dff348347f93', 1)^