Generate, validate, and modify Nop ORM models from MySQL DDL/SQL or business requirements. Covers entity modeling, relationships, domains, dictionaries, displayName localization, and ORM file organization (Delta mode). Use for database-first or requirements-first ORM development.
本 skill 的核心目标是构建/修改/维护 Nop 平台的 ORM 模型文件(.orm.xml)。
重要原则:
.orm.xml 为准。当你的需求涉及以下场景时,请加载此 skill:
| 场景 | 触发关键词 | 示例 |
|---|---|---|
| 从 DDL/SQL 生成 ORM | "DDL", "SQL", "数据库表", "生成 ORM" | "从 {ddl-file.sql} 生成 {appName} 的 ORM" |
| 根据需求建模 | "需求", "实体", "建模", "创建 ORM" | "根据需求文档生成 {moduleName} 的 ORM" |
| 修改/补全 ORM | "displayName", "补全标签", "添加字段" | "补全 {appName}-delta-1.orm.xml 的中文标签" |
| 验证 ORM 配置 | "验证", "检查", "review" | "验证生成的 ORM 文件配置是否正确" |
使用本 skill 前,确认以下工具存在:
| 工具 | 用途 | 必需性 |
|---|---|---|
generate_orm_from_mysql_ddl.py | 从 DDL 生成 ORM | DDL 场景必需 |
extract_labels_to_markdown.py | 抽取多语言标签 | 可选 |
apply_labels_from_markdown.py | 回填标签到 ORM | 可选 |
| DDL 文件或需求文档 | 输入源 | 必需 |
根据输入类型选择处理方式:
| 输入类型 | 处理方式 |
|---|---|
| 已有 DDL/SQL 文件 | 使用 generate_orm_from_mysql_ddl.py 自动化生成 |
| 无 DDL,只有需求文档 | 根据需求直接建模,生成 ORM 文件 |
当有 DDL/SQL 文件时,必须使用 generate_orm_from_mysql_ddl.py 脚本:
python3 generate_orm_from_mysql_ddl.py \
--sql <DDL文件路径> \
--out <输出ORM文件路径> \
--app-name <应用名> \
--base-package <基础包名> \
--entity-package <实体包名> \
--dialect <数据库类型>
示例:
python3 generate_orm_from_mysql_ddl.py \
--sql ./tables.sql \
--out ./my-app-delta-1.orm.xml \
--app-name my-app \
--base-package com.example.myapp \
--entity-package com.example.myapp.dao.entity \
--dialect mysql
脚本生成内容:
脚本不会生成(需后续补充):
当没有 DDL,只有需求文档时,直接根据需求生成 ORM:
将实体按业务模块分组,每组约 20 个表。
每个模块生成一个 delta 文件(不含 dicts 和 domains):
{appName}-delta-1.orm.xml (核心业务实体 ~20个)
{appName}-delta-2.orm.xml (工作流实体 ~20个)
{appName}-delta-3.orm.xml (扩展功能实体 ~20个)
...
主文件只包含公共配置(domains、dicts),通过 x:extends 引用所有 delta 文件:
<?xml version="1.0" encoding="UTF-8"?>
<orm ext:registerShortName="true" ext:appName="{appName}"
ext:entityPackageName="com.example.{appName}.dao.entity"
ext:basePackageName="com.example.{appName}"
x:extends="{appName}-delta-1.orm.xml,{appName}-delta-2.orm.xml,{appName}-delta-3.orm.xml"
x:schema="/nop/schema/orm/orm.xdef" xmlns:x="/nop/schema/xdsl.xdef" >
<domains>
<!-- 公共 domain 定义 -->
</domains>
<dicts>
<!-- 公共 dict 定义 -->
</dicts>
<entities>
<!-- 空,只通过 x:extends 引用 delta 文件 -->
</entities>
</orm>
注意:delta 文件必须是完整的 ORM 结构,但不包含 dicts 和 domains。
| 文件类型 | 命名格式 | 示例 |
|---|---|---|
| Delta 文件 | {appName}-delta-{序号}.orm.xml | my-app-delta-1.orm.xml |
| 主文件 | {appName}.orm.xml | my-app.orm.xml |
使用标签抽取脚本补全多语言展示名:
# 抽取标签到 Markdown
python3 extract_labels_to_markdown.py <orm.xml> > labels.md
# AI 填写 displayName/enDisplayName
# 回填到 ORM
python3 apply_labels_from_markdown.py <orm.xml> labels.md
规则:
displayNameenDisplayName(回填到 i18n-en:displayName)ext:appName 符合 {子系统}-{模块} 格式,全小写 ASCIIext:basePackageName 正确设置,如 com.example.myappext:entityPackageName = {basePackageName}.dao.entityext:mavenGroupId / ext:mavenArtifactId 正确ext:dialect 包含目标数据库方言{prefix}_*)user、order){子系统前缀}_{模块}_{实体} 格式DemoEntity)com.example.myapp.dao.entity.DemoEntity)primary="true", tagSet="seq"propId 从 1 开始连续递增,无重复,无空缺APPLICATION_ID、USER_NAME)applicationId、userName)stdSqlType 必须使用 StdSqlType 枚举类的标准值
ext:dict="xxx/yyy"(注意:boolean 型字段不用设置 dict)domain 使用原则:
refEntityName 指向的实体存在leftProp 和 rightProp 对应的字段存在tagSet="pub"tagSet="pub,cascade-delete,insertable,updatable"cascadeDelete="true" 用于主从表)refPropName)refPropName 在子表上存在primary="true")unique-key(如用户名、订单号)UK_{APP_NAME}_USER_NAME){appName}/
├── model/
│ ├── {appName}.orm.xml # 主文件(包含 domains、dicts、x:extends)
│ ├── {appName}-delta-1.orm.xml # Delta 文件 1(核心业务实体)
│ ├── {appName}-delta-2.orm.xml # Delta 文件 2(工作流实体)
│ └── {appName}-delta-3.orm.xml # Delta 文件 3(扩展功能实体)
<?xml version="1.0" encoding="UTF-8"?>
<orm ext:registerShortName="true" ext:appName="{appName}"
ext:entityPackageName="com.example.{appName}.dao.entity"
ext:basePackageName="com.example.{appName}"
ext:mavenGroupId="com.example" ext:mavenArtifactId="{appName}"
ext:dialect="mysql" ext:useStdFields="true"
x:extends="{appName}-delta-1.orm.xml,{appName}-delta-2.orm.xml,{appName}-delta-3.orm.xml"
x:schema="/nop/schema/orm/orm.xdef" xmlns:x="/nop/schema/xdsl.xdef" >
<domains>
<!-- 公共 domain 定义 -->
</domains>
<dicts>
<!-- 公共 dict 定义 -->
</dicts>
<entities>
<!-- 留空,通过 x:extends 引用 -->
</entities>
</orm>
<?xml version="1.0" encoding="UTF-8"?>
<orm ext:registerShortName="true" ext:appName="{appName}"
ext:entityPackageName="com.example.{appName}.dao.entity"
ext:basePackageName="com.example.{appName}"
ext:dialect="mysql" ext:useStdFields="true"
x:schema="/nop/schema/orm/orm.xdef" xmlns:x="/nop/schema/xdsl.xdef" >
<!-- 不包含 domains 和 dicts -->
<entities>
<entity ...>
<columns>...</columns>
<relations>...</relations>
</entity>
<!-- 更多实体 -->
</entities>
</orm>
A: 创建中间表实体:
<!-- 中间表 -->
<entity name="com.xxx.dao.entity.AppUserRole">
<columns>
<column name="userId" code="USER_ID" .../>
<column name="roleId" code="ROLE_ID" .../>
</columns>
<relations>
<to-one name="user" refEntityName="com.xxx.dao.entity.AppUser"
tagSet="pub">
<join><on leftProp="userId" rightProp="userId"/></join>
</to-one>
<to-one name="role" refEntityName="com.xxx.dao.entity.AppRole"
tagSet="pub">
<join><on leftProp="roleId" rightProp="roleId"/></join>
</to-one>
</relations>
</entity>
<!-- 用户实体 -->
<to-many name="roles" refEntityName="com.xxx.dao.entity.AppUserRole"
refPropName="user" tagSet="pub,cascade-delete,insertable,updatable">
<join><on leftProp="userId" rightProp="userId"/></join>
</to-many>
A: 例如用户上级关系:
<column name="managerId" code="MANAGER_ID" .../>
<to-one name="manager" refEntityName="com.xxx.dao.entity.AppUser"
tagSet="pub">
<join><on leftProp="managerId" rightProp="userId"/></join>
</to-one>
<to-many name="subordinates" refEntityName="com.xxx.dao.entity.AppUser"
refPropName="manager" tagSet="pub,cascade-delete,insertable,updatable">
<join><on leftProp="userId" rightProp="managerId"/></join>
</to-many>
A: 使用 ext:dict:
<!-- 字段定义 -->
<column name="status" code="STATUS" displayName="用户状态"
ext:dict="{app}/application-status" stdDataType="int" stdSqlType="INTEGER"/>
<!-- 字典定义 -->
<dict name="{app}/application-status" label="申请状态" valueType="int">
<option code="CREATED" label="已创建" value="10"/>
<option code="PROCESSING" label="处理中" value="20"/>
<option code="COMPLETED" label="已完成" value="30"/>
<option code="CANCELLED" label="已取消" value="40"/>
</dict>
dict 配置规范:
int 类型,便于数值比较和排序INTEGER,不要使用 TINYINT 或 SMALLINT
stdSqlType="BOOLEAN" 即可option code 格式要求:
CREATED, AUTO_CANCEL)A: domain 用于定义具有特殊业务规则的字段类型:
applicationId(申请ID,50字符 VARCHAR)userId(用户ID,255字符 VARCHAR)creditLimit(额度,DECIMAL(38,4))createTime/updateTime(时间,TIMESTAMP)version(版本号,INTEGER)示例:
<!-- domains 定义 -->
<domain name="applicationId" precision="50" stdSqlType="VARCHAR"/>
<!-- 字段定义 -->
<column name="applicationId" code="APPLICATION_ID" displayName="申请编号"
domain="applicationId" mandatory="true" stdSqlType="VARCHAR"/>
User: "从 {ddl-file.sql} 生成 {appName} 的 ORM,按 20 表一个文件拆分" AI:
User: "补全 {appName}-delta-1.orm.xml 的中文标签" AI:
extract_labels_to_markdown.pyapply_labels_from_markdown.py 回填User: "根据需求文档生成 {moduleName} 的 ORM,实体列表在文档第 5 节" AI:
generate_orm_from_mysql_ddl.py(DDL 转 ORM 脚本)extract_labels_to_markdown.py(抽取标签脚本)apply_labels_from_markdown.py(回填标签脚本)orm.xdef|entity.xdef|dict.xdef(元模型)app-sample.orm.xml(示例)生成/修改 ORM 时遇到问题,按以下优先级排查:
generate_orm_from_mysql_ddl.py 存在且参数正确| 错误现象 | 可能原因 | 解决方法 |
|---|---|---|
| 生成文件为空 | DDL 路径错误或文件格式不对 | 检查 --sql 参数指向的文件存在且有效 |
| 缺少外键关系 | 脚本只生成 to-one,不生成 to-many | 手动补充 to-many 关系配置 |
| displayName 全为空 | 未运行标签回填脚本 | 执行 apply_labels_from_markdown.py |
| x:extends 报错 | delta 文件结构不完整 | 确认 delta 文件包含完整的 <entities> 根节点 |
| domain 报错 | domain 名称重复或类型不匹配 | 检查 domain 命名唯一性 |
生成 ORM 文件后,使用 nop-cli validate 验证:
nop-cli validate my-app.orm.xml