专门用于设计、创建、验证和修改Nop平台的ORM模型文件(.orm.xml)
Installation
$skills install @entropy-cloud/nop-orm-modeler
Claude Code
Cursor
Copilot
Codex
Antigravity
Details
Repositoryentropy-cloud/nop-entropy
Path.opencode/skill/nop-orm-modeler/SKILL.md
Branchmaster
Scoped Name@entropy-cloud/nop-orm-modeler
Usage
After installing, this skill will be available to your AI coding assistant.
Verify installation:
skills listSkill Instructions
name: nop-orm-modeler description: 专门用于设计、创建、验证和修改Nop平台的ORM模型文件(.orm.xml)
使用场景
- 新增: "创建"、"新增"、"增加" → 创建实体/字段/关系
- 更新: "修改"、"更新"、"调整" → 修改现有定义
- 检查并修正: "检查并修正"、"检查规范" → 仅修正格式规范,不碰业务逻辑
What I do
我是Nop 平台 ORM 模型专家,设计/创建/修改 .orm.xml 文件。
元模型参考
- orm.xdef:domains、dicts、entities 定义
- entity.xdef:columns、relations、indexes、unique-keys 定义
- dict.xdef:数据字典定义
根节点配置说明
ext:appName
- 模块标识名,生成
{appName}.orm.xml - 两级结构:
{xx}-{yy},全小写 ASCII - 例:
app-test→app-test.orm.xml
ext:basePackageName
- 模块基础包名
- 代码分层:dao, service 等
- 例:
io.app.sample→io.app.sample.dao,io.app.sample.service
ext:entityPackageName
- 实体类包名
- 一般为
{basePackageName}.dao.entity - 例:
io.app.sample.dao.entity
其他 ext 属性
- mavenGroupId / mavenArtifactId:Maven 坐标
- dialect:数据库方言,如
mysql,oracle,postgresql - useStdFields:是否使用标准字段,默认
truetrue:自动添加 CREATE_TIME 等审计字段(见下方"Nop 平台特定规则")false:不自动添加标准字段
Nop 平台特定规则
重要:以下字段由平台自动添加,无需手动定义:
| 字段 | 类型 | 说明 |
|---|---|---|
| CREATED_BY | VARCHAR(50) | 创建者 |
| CREATE_TIME | TIMESTAMP | 创建时间 |
| UPDATED_BY | VARCHAR(50) | 更新者 |
| UPDATE_TIME | TIMESTAMP | 更新时间 |
| DEL_VERSION | BIGINT | 逻辑删除 |
| VERSION | INTEGER | 乐观锁版本 |
XDef 基本说明
XDef 是 XLang 的领域模型定义语法,特点:
- 与领域描述同形,Tree 结构一致
- 集合元素通过
xdef:key-attr定义唯一标识 - 支持类型标注、默认值
- 自动支持差量分解和合并
类型描述符格式:(!~#)?{stdDomain}:{options}={defaultValue}
!:必填~:内部或废弃#:支持编译期表达式
节点类型:
- 普通属性:
name="!string" - 集合节点:
xdef:body-type="list" - 唯一标识:
xdef:key-attr="id" - 节点复用:
xdef:ref="WorkflowStepModel"
设计原则
命名规范
- Java 属性:驼峰(
userId) - 数据库列名:大写下划线(
USER_ID) - 实体类名:大驼峰(
AppSampleUser) - 表名必须带统一子系统前缀:
{子系统前缀}_{功能模块}_{实体名}- ✅ 正确:
app_sample_user、app_order_item - ❌ 错误:
user、order(缺少前缀) - 前缀示例:
app_sample(示例模块)、app_order(订单模块)、app_sys(系统模块)
- ✅ 正确:
- 不要使用 nop 前缀:
nop前缀保留给 Nop 平台内置模块使用,用户自定义模块不应使用- ❌ 错误:
nop_auth_user、nop-auth.orm.xml - ❌ 错误:
io.nop.auth(包名) - ✅ 正确:
app_auth_user、app-auth.orm.xml - ✅ 正确:
io.app.auth(包名)
- ❌ 错误:
关系映射
- to-one:子表添加外键列,缺省
tagSet="pub" - to-many:主表定义集合属性,缺省
tagSet="pub,cascade-delete,insertable,updatable" - 多对多:创建中间表实体
索引设计
- 主键索引自动创建
- 外键列自动索引
- 业务唯一键定义 unique-key
生成完成后的必检项
重要:生成 .orm.xml 文件后,必须逐项检查以下内容:
1. 根节点配置
-
ext:appName符合{xx}-{yy}格式,全小写 ASCII -
ext:basePackageName正确设置,如io.app.sample -
ext:entityPackageName={basePackageName}.dao.entity -
ext:mavenGroupId/ext:mavenArtifactId正确 -
ext:dialect包含目标数据库方言
2. 表名规范
- 所有表名带统一子系统前缀(如
app_sample_user) - 不能是简单单词(如
user、order) - 遵循
{子系统前缀}_{模块}_{实体}格式
3. 实体定义
- 实体类名符合大驼峰规范(
AppSampleUser) - 完整包名正确(
io.app.sample.dao.entity.AppSampleUser) - 主键配置:
primary="true",tagSet="seq" - 未手动添加审计字段(CREATED_BY, CREATE_TIME, UPDATED_BY, UPDATE_TIME, DEL_VERSION, VERSION)
4. 字段定义
-
propId从 1 开始连续递增,无重复,无空缺 - 列名符合大写下划线规范(
USER_ID、USER_NAME) - 字段名符合驼峰规范(
userId、userName) -
stdSqlType必须使用 StdSqlType 枚举类的标准值- 可用的 stdSqlType 值:BOOLEAN|TINYINT|SMALLINT|INTEGER|BIGINT|DECIMAL|FLOAT|DOUBLE|DATE|TIME|DATETIME|TIMESTAMP|CHAR|VARCHAR|VARBINARY|CLOB|BLOB
- 枚举字段配置
ext:dict="xxx/yyy"(注意:boolean 型字段不用设置 dict) -
domain使用原则:- 不是每个字段都需要 domain,只有具有重要业务含义、在显示或后台处理方面存在特殊业务规则的字段才需要定义 domain
- 例如:订单编号(order-no)可能需要特殊编号规则、状态字段需要特殊显示逻辑等
- 优先复用
app-sample.orm.xml中已有的 domain,domain 是全局的,不能重名 - 能复用的一定要复用,避免重复定义
5. 关系定义
-
refEntityName指向的实体存在 - join 条件正确:
leftProp和rightProp对应的字段存在 - to-one 关系设置
tagSet="pub" - to-many 关系设置
tagSet="pub,cascade-delete,insertable,updatable" - 级联删除配置合理(
cascadeDelete="true"用于主从表) - 反向引用名称合理(
refPropName) - 一对多关系的
refPropName在子表上存在
6. 索引和约束
- 主键索引已定义(
primary="true") - 业务唯一键定义了
unique-key(如用户名、订单号) - 外键列有索引(Nop 自动生成,可显式定义)
- 约束名唯一且有前缀(如
UK_APP_SAMPLE_USER_NAME)
常见问题
Q1: 多对多关系?
A: 创建中间表实体:
<!-- 中间表 -->
<entity name="io.app.sample.dao.entity.AppSampleUserRole">
<columns>
<column name="userId" code="USER_ID" .../>
<column name="roleId" code="ROLE_ID" .../>
</columns>
<relations>
<to-one name="user" refEntityName="io.app.sample.dao.entity.AppSampleUser"
tagSet="pub">
<join><on leftProp="userId" rightProp="userId"/></join>
</to-one>
<to-one name="role" refEntityName="io.app.sample.dao.entity.AppSampleRole"
tagSet="pub">
<join><on leftProp="roleId" rightProp="roleId"/></join>
</to-one>
</relations>
</entity>
<!-- 用户实体 -->
<to-many name="roles" refEntityName="io.app.sample.dao.entity.AppSampleUserRole"
refPropName="user" tagSet="pub,cascade-delete,insertable,updatable">
<join><on leftProp="userId" rightProp="userId"/></join>
</to-many>
Q2: 自关联关系?
A: 例如用户上级关系:
<column name="managerId" code="MANAGER_ID" .../>
<to-one name="manager" refEntityName="io.app.sample.dao.entity.AppSampleUser"
tagSet="pub">
<join><on leftProp="managerId" rightProp="userId"/></join>
</to-one>
<to-many name="subordinates" refEntityName="io.app.sample.dao.entity.AppSampleUser"
refPropName="manager" tagSet="pub,cascade-delete,insertable,updatable">
<join><on leftProp="userId" rightProp="managerId"/></join>
</to-many>
Q3: 枚举字段?
A: 使用 ext:dict:
<!-- 字段定义 -->
<column name="status" code="STATUS" displayName="用户状态"
ext:dict="app-sample/user-status" stdDataType="int" stdSqlType="TINYINT"/>
<!-- 字典定义 -->
<dict name="app-sample/user-status" label="用户状态" valueType="int">
<option code="NORMAL" label="正常" value="0"/>
<option code="DISABLED" label="禁用" value="1"/>
<option code="LOCKED" label="锁定" value="2"/>
</dict>
注意:
- boolean 型字段不用设置 dict,直接使用
stdSqlType="BOOLEAN"即可 - dict 主要用于具有多个离散值的枚举类型(如状态、类型等)
option code 格式要求:
- 全大写字母,使用下划线分隔(如
CREATED,AUTO_CANCEL,GROUPON_EXPIRED) - 语义清晰,能表达状态含义(如
CREATED表示已创建,PAY表示已付款) - 不要使用缩写(如
AUTO_CANCEL而非AUTO_CNL)
Q4: 如何使用 domain?
A: domain 用于定义具有特殊业务规则的字段类型:
- 不是每个字段都需要 domain,只有具有重要业务含义的字段才需要
- 优先复用
app-sample.orm.xml中已有的 domain(domain 是全局的,不能重名) - 常见的可复用 domain:
userName(用户名,50字符 VARCHAR)email(邮箱,100字符 VARCHAR)phone(电话,100字符 VARCHAR)userId(用户ID,50字符 VARCHAR)deptId(部门ID,50字符 VARCHAR)remark(备注,1000字符 VARCHAR)createTime/updateTime(时间,TIMESTAMP)createdBy/updatedBy(操作人,50字符 VARCHAR)
示例:订单编号需要特殊格式验证
<!-- domains 定义 -->
<domain name="orderNo" precision="32" stdSqlType="VARCHAR"/>
<!-- 字段定义 -->
<column name="orderNo" code="ORDER_NO" displayName="订单编号"
domain="orderNo" mandatory="true" stdSqlType="VARCHAR"/>
生成注意事项
文件保存位置
默认位置:{appName}/model 目录下
- 例:
app-sample模块 →app-sample/model/app-sample.orm.xml
appName 不确定时:使用 app-xxx 格式,根据业务语义推断
大文件拆分(Delta 模式)
内容过多时拆分为多个 delta 文件:
文件结构:
- Delta 文件:
app-demo-delta-1.orm.xml、app-demo-delta-2.orm.xml...- 每个 delta 都是完整 orm.xml,但不含 dicts 和 domains
- 主文件:
app-demo.orm.xml- 通过
x:extends="app-demo-delta-1.orm.xml,app-demo-delta-2.orm.xml"引用 - 只包含 delta 文件以外的内容
- 通过
合并规则:
- Delta 逐层叠加,高层覆盖底层
- 重复定义以高层为准
- 类似 Docker 分层机制
参考文件
- 本目录:
orm.xdef|entity.xdef|dict.xdef(元模型) - 本目录:
app-sample.orm.xml(示例)
