|
@@ -257,6 +257,104 @@ public async up(queryRunner: QueryRunner): Promise<void> {
|
|
|
|
|
|
|
|
---
|
|
---
|
|
|
|
|
|
|
|
|
|
+## 常见陷阱与解决方案
|
|
|
|
|
+
|
|
|
|
|
+### ⚠️ 迁移文件命名规范(重要!)
|
|
|
|
|
+
|
|
|
|
|
+**问题**:迁移文件必须以数字结尾才能被 Glob 模式匹配。
|
|
|
|
|
+
|
|
|
|
|
+| 文件名 | 是否匹配 `*[0-9].ts` | 说明 |
|
|
|
|
|
+|--------|---------------------|------|
|
|
|
|
|
+| `Migrate...1737260000000.ts` | ✅ 匹配 | 以数字结尾 |
|
|
|
|
|
+| `1768968781678-Create...Table.ts` | ❌ 不匹配 | 以字母结尾 |
|
|
|
|
|
+
|
|
|
|
|
+**正确命名格式**:
|
|
|
|
|
+```
|
|
|
|
|
+[描述性名称][时间戳].ts
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+示例:`CreateDisabledPersonPhoneTable1768968781678.ts`
|
|
|
|
|
+
|
|
|
|
|
+### ⚠️ 迁移类必须包含 name 属性
|
|
|
|
|
+
|
|
|
|
|
+```typescript
|
|
|
|
|
+export class CreateDisabledPersonPhoneTable1768968781678 implements MigrationInterface {
|
|
|
|
|
+ name = 'CreateDisabledPersonPhoneTable1768968781678'; // 必须有!
|
|
|
|
|
+
|
|
|
|
|
+ public async up(queryRunner: QueryRunner): Promise<void> {
|
|
|
|
|
+ // ...
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+没有 `name` 属性会导致迁移无法被 TypeORM CLI 识别。
|
|
|
|
|
+
|
|
|
|
|
+### ⚠️ 主键列名差异
|
|
|
|
|
+
|
|
|
|
|
+**问题**:不同表可能使用不同的主键列名。
|
|
|
|
|
+
|
|
|
|
|
+```typescript
|
|
|
|
|
+// ❌ 错误:假设所有表都用 id 作为主键
|
|
|
|
|
+referencedColumnNames: ["id"]
|
|
|
|
|
+
|
|
|
|
|
+// ✅ 正确:检查实际表的主键列名
|
|
|
|
|
+// disabled_person 表的主键是 person_id,不是 id!
|
|
|
|
|
+referencedColumnNames: ["person_id"]
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+**解决方法**:在创建外键前,先检查被引用表的实际主键列名:
|
|
|
|
|
+```bash
|
|
|
|
|
+psql -h 127.0.0.1 -U postgres -c "\d+ table_name"
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+### ⚠️ migration:generate 可能失败
|
|
|
|
|
+
|
|
|
|
|
+**问题**:TypeORM 有时无法检测实体变化,报告 "No changes in database schema were found"。
|
|
|
|
|
+
|
|
|
|
|
+**可能原因**:
|
|
|
|
|
+1. 实体文件没有被 Glob 模式正确加载
|
|
|
|
|
+2. 实体与数据库表已完全同步
|
|
|
|
|
+3. TypeScript 编译问题
|
|
|
|
|
+
|
|
|
|
|
+**解决方案**:手动创建迁移文件
|
|
|
|
|
+```typescript
|
|
|
|
|
+import { MigrationInterface, QueryRunner, Table, TableForeignKey } from "typeorm";
|
|
|
|
|
+
|
|
|
|
|
+export class YourMigrationTimestamp implements MigrationInterface {
|
|
|
|
|
+ name = 'YourMigrationTimestamp';
|
|
|
|
|
+
|
|
|
|
|
+ public async up(queryRunner: QueryRunner): Promise<void> {
|
|
|
|
|
+ // 手动编写迁移逻辑
|
|
|
|
|
+ await queryRunner.createTable(
|
|
|
|
|
+ new Table({
|
|
|
|
|
+ name: "your_table",
|
|
|
|
|
+ columns: [/* ... */],
|
|
|
|
|
+ }),
|
|
|
|
|
+ true
|
|
|
|
|
+ );
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ public async down(queryRunner: QueryRunner): Promise<void> {
|
|
|
|
|
+ await queryRunner.dropTable("your_table", true);
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+### ⚠️ 更新 migrations/index.ts
|
|
|
|
|
+
|
|
|
|
|
+创建迁移文件后,必须更新 `packages/server/migrations/index.ts`:
|
|
|
|
|
+
|
|
|
|
|
+```typescript
|
|
|
|
|
+import { YourMigrationTimestamp } from './YourMigrationTimestamp';
|
|
|
|
|
+
|
|
|
|
|
+export const migrations: any[] = [
|
|
|
|
|
+ MigrateNotWorkingToPreWorking1737260000000,
|
|
|
|
|
+ YourMigrationTimestamp, // 按时间戳顺序添加
|
|
|
|
|
+]
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+---
|
|
|
|
|
+
|
|
|
## 注意事项
|
|
## 注意事项
|
|
|
|
|
|
|
|
### ⚠️ 生产环境迁移
|
|
### ⚠️ 生产环境迁移
|