命名策略与表结构
模型不写任何表名/列名也能生成 SQL——因为有一个命名策略在背后做规则推导。
默认策略:UPPER_SNAKE_CASE
spi.UPPER_SNAKE_CASE_DATABASE_NAMING_STRATEGY(构建 SqlClient 的默认值):
| 模型侧 | 推导结果 | 例子 |
|---|---|---|
| 模型名 | 大写蛇形表名 | BookStore → BOOK_STORE |
| 属性名 | 大写蛇形列名 | edition → EDITION |
| m2o 外键列 | 属性名 + _ID | store → STORE_ID |
| 中间表 m2m | 两侧模型名拼接 | Book + Author → BOOK_AUTHOR_MAPPING(配 joinTable 名则显式) |
| 继承子表主键 | 模型缩写 + _ID | PaperBook → PB_ID(可用 idMapping 显式覆盖) |
自定义策略
需要贴合既有库(非驼峰转写的表/列名)时,实现 DatabaseNamingStrategy:
import { spi } from '@ts-grm/core'
const LOWER_SNAKE: spi.DatabaseNamingStrategy = {
tableName(entity) { return toLowerSnake(entity.name) },
columnName(prop) { return toLowerSnake(prop.name) },
// sequenceName / middleTableName / middleTableThisRefColumnName / middleTableTargetRefColumnName
// 未覆写的只影响对应场景,也可全部手写
}
const client = newSqlClient(driver, { strategy: { namingStrategy: LOWER_SNAKE, keywordStrategy: ... } })
接口还有 keywordStrategy(保留字处理)。若不自定义,就用默认策略 + 下面两种显式覆盖。
显式覆盖:表名与列名
- 模型级:配置器
ctx.table({ name: "实际表名" })覆盖表名(别名/旧库迁移场景); - 关联列:
joinColumns({ columns: [{ columnName, referencedSubPath }] })(复合外键列名,见「复合值 embedded」); - 继承主键:
name: { idMapping: "STORE_ID" }(继承页已用); - embedded:成员列名 = 成员名本身(
name.firstName→FIRST_NAME,无路径前缀)。
表结构由模型驱动
createSchema() / 实体管理器能从模型一键生成建表 DDL(含主键、外键、多态 check 约束)——声明即 schema(「模式创建与实体管理器」页)。手工建表时,按上面的命名规则对齐也一样。