数据模型定义

知识点

  • entity: entity-name, package cache
    • field: type, is-pk
      • 自定义 type: 配置XML文件中: database-list.dictionary-type
    • relationship
      • 到 Enumeration实体的外键,约定: title属性和enumTypeId匹配
      • key-map
  • 其他实体属性
    • group_name
    • sequence-bank-size, sequence-primary-stagger, sequence-secondary-padded-length
    • optimistic-lock
    • no-update-stamp
    • cache
    • authorize-skip
  • 其他字段属性
    • encrypt, enable-audit-log, enable-localization
  • index
  • 在独立模块中扩展其他模块的实体: extend-entity

实体定义XML

先看个显示最常用元素的简单实体定义。这是Moqui框架中的一个实际的实体:

<entity entity-name="DataSource" package="moqui.basic" cache="true">
     <field name="dataSourceId" type="id" is-pk="true"/>
     <field name="dataSourceTypeEnumId" type="id"/>
     <field name="description" type="text-medium"/>
     <relationship type="one" title="DataSourceType" related="Enumeration">
        <key-map field-name="dataSourceTypeEnumId"/>
     </relationship>
     <seed-data>
         <moqui.basic.EnumerationType description="Data Source Type" enumTypeId="DataSourceType"/>
         <moqui.basic.Enumeration description="Purchased Data" enumId="DST_PURCHASED_DATA" enumTypeId="DataSourceType"/>;
     </seed-data>
</entity>

就像Java类,一个实体有一个包名,实体的全名是包名加实体名,格式为:

${package}.${entity-name}

基于此模式,此实体的全名为: moqui.basic.DataSource

此例把 entity.cache 属性设为 true,意味着如果执行查询的代码不说其他选项的话,它将被缓存。

第一个字段(dataSourceId)的is-pk属性设置为true,意思是它是实体的主键字段之一。在这个例子中它是唯一的主键字段,但是可以设置任意数量的字段的这个属性为true,使得它们成为主键的部分。

第三个字段(description)是一个简单的保存数据的字段。它不是主键的一部分,也不是到其他实体的外键。

field.type属性被用来指定字段的数据类型。默认选项在MoquiDefaultConf.xml文件中用 database-list.dictionary-type 元素定义。这些元素为每个字典了些指定默认的类型设定,并且对于每个数据库,可以用 database.database-type 元素覆盖。

    <database-list>
        <dictionary-type type="id" java-type="java.lang.String" default-sql-type="VARCHAR(40)"/>
        <dictionary-type type="id-long" java-type="java.lang.String" default-sql-type="VARCHAR(255)"/>

        <dictionary-type type="date" java-type="java.sql.Date" default-sql-type="DATE"/>
        <dictionary-type type="time" java-type="java.sql.Time" default-sql-type="TIME"/>
        <dictionary-type type="date-time" java-type="java.sql.Timestamp" default-sql-type="TIMESTAMP"/>

        <!-- 其他省略 -->

    </database-list>

你能使用这些元素来在数据类型字典中添加你自己的类型。那些自定义类型不会出现在你的XML编辑器field.type属性的自动完成中,除非你也修改XSD文件在其中加入自定义类型,但它们仍然能用。

第二个字段(dataSourceTypeEnumId)是一个到Enumeration实体的外键,如实体定义中的relationship元素所示。seed-data元素内的两条记录定义了EnumerationType来对枚举选项进行分组,其中一条是给dataSourceTypeEnumId字段的。seed-data元素下的记录在命令行-load选项(或对应的API调用)有seed类型时被加载。

这里有一个重要的模式让框架知道使用哪个enumTypeId来在自动生成表单字段等场合为一个字段过滤Enumeration选项。注意relationship.title属性的值和enumTypeId匹配。换句话说,对于枚举,有个约定就是relationship.title值是用来过滤列表的类型ID。

这是一个在Moqui和Mantle业务构件中用得非常多的模式,因为Enumeration实体被用来为许多不同的实体管理可用的类型。

@startuml

class DataSource {
    pk dataSourceId
    id dataSourceTypeEnumId
}

class EnumerationType {
    id enumTypeId
}
class Enumeration {
    enumTypeId="DataSourceType"
    enumId="DST_PURCHASED_DATA"
}

EnumerationType .. Enumeration
DataSource . Enumeration : "title属性的值和enumTypeId匹配\ndataSourceTypeEnumId字段和Enumeration的主键(enumId)对应"


@enduml

在本例中,在relationship元素下有一个key-map元素,但那只在实体上的字段名与关联实体上相关联的字段名不一致时才需要。也就是说,因为外键字段名为dataSourceTypeEnumId而不是简单的enumId,我们需要告诉框架使用哪个字段。框架知道关联实体(本例中是Enumeration)上哪些字段是主键,但是如果字段名不与其匹配,它就不知道这个实体上哪些字段与那些字段对应。

在很多案例中,你可以像这样简单使用而不需要用key-map元素:

<relationship type="one" related="Enumeration"/>

seed-data元素允许你定义实体使用所需的基础数据,并且是定义数据模型的一个方面。当entity-facade-xml文件的type属性设置为seed时,这些数据和entity-facade-xml文件一起被加载到数据库中。

介绍了实体定义最常用的这些元素后,让我们看看实体定义中可用的一些其他元素和属性:

  • 其他实体属性
    • group-name: 通过EntityFacade可用的每个数据源被使用的方法,都是把一个实体放入该数据源所在的组。这里的值应该和Moqui配置XML文件中的moqui-conf.entity-facade.datasource.group_name上的一个值匹配。如果没有指定此值,那么将默认使用moqui-conf.entity-facade.default-group-name属性的值。默认配置中有效的值包括transactional(默认),analytical,tenantcommon,和nosql
    • sequence-bank-size: 保存在内存中的序列池的大小。每次内存池用尽了,SequenceValueItem记录中的seqNum将会增加这么多数量。
    • sequence-primary-stagger: 序列ID错开的最大数。如果值为1,那么序列将会按1增长,否则当前序列ID将会在1和staggerMax直接随机增长。
    • sequence-secondary-padded-length: 如果指定了,则在secondary序列值前填零,直到序列值长度为此长度。默认为2。
    • optimistic-lock: 如果设置为true,那么EntityFacade会在对记录执行更新操作前比较内存和数据库中的lastUpdatedStamp字段。如果时间戳不匹配,将会产生一个错误。默认为"false"(没有时间戳锁定)。
    • no-update-stamp: 默认情况下EntityFacade会给每个实体加一个字段(lastUpdatedStamp)用于乐观锁和数据同步。如果不想创建那个时间戳字段,那么将这个设为"false"。
    • cache: 可以设为这些值(默认为false):
      • true: 为查找使用缓存(也许会被代码覆盖)
      • false: 不为查找设立缓存(也许会被代码覆盖)
      • never: 不为查找设立缓存(代码不能覆盖)
    • authorize-skip: 可以设为这些值(默认为false):
      • true: 忽略对这个实体的所有鉴权检查
      • false: 不能忽略鉴权检查
      • create: 为创建操作忽略鉴权检查
      • view: 为查找或只读操作忽略鉴权检查
      • view-create: 为查找和创建操作忽略鉴权检查
  • 其他字段属性
    • encrypt:设为true则在数据库中加密此字段。默认为false(不加密)
    • enable-audit-log: 设置为 true 则把对此字段的所有变更加上变更时间、变更用户信息写到日志。设置为 update 则记录下所有变更但不包括初始值(当字段值不变时会轻量级一点)。日志数据使用EntityAuditLog实体保存。默认为 false (没有审计日志)
    • enable-localization: 如果设置为true,将会查找LocalizedEntityField实体,如果有一个匹配的记录,那么本地化的值将取代原始记录值被返回。出于性能原因,默认为false,只为要翻译的字段设置为true。

因为某些数据库优化必须在数据库本身实现,许多这样的特性在数据库之间有不同,你可以用index元素和实体定义一起声明索引。作为一个在entity元素下的元素,像这样:

<index name="EX_NAME_IDX1" unique="true">
    <index-field name="exampleName"/>
</index>

实体扩展 - XML

可以不改原始定义的XML文件就可以扩展实体。当你想扩展一个其他组件甚至Moqui框架中的实体(例如Mantle同意数据模型mantle-udm)并且想保持你的扩展的独立性时这特别有用。

用一个可以在实体定义XML文件中与entity元素混合的extend-entity元素来实现这个。此元素像定义原始实体的entity元素一样有很多同样的属性和子元素。很简单,确保entity-namepackage属性和原始entity元素的同意属性匹配就行了,你指定的其他内容将会被添加或覆盖到原始实体。

下面是一个扩展moqui.example.Example实体的XML片段:

<extend-entity entity-name="Example" package="moqui.example">
    <field name="auditedField" type="text-medium" enable-audit-log="true"/>
    <field name="encryptedField" type="text-medium" encrypt="true"/>
</extend-entity>

results matching ""

    No results matching ""