TypeORM复合外键

TypeORM composite foreign key

在第一个class中,主键是复合的:

@Entity({
  name: 'ClassA',
  database: Constants.DATABASE_NAME,
})
export class ClassA {
  @PrimaryColumn({
    name: 'Field1',
    type: 'varchar',
    length: 4,
  })
  field1: string;

  @PrimaryColumn({
    name: 'Field2',
    type: 'varchar',
    length: 2,
  })
  field2: string;

  @PrimaryColumn({
    name: 'Field3',
    type: 'integer',
  })
  field3: number;

  @OneToMany(() => ClassB, (classB) => classB.classA)
  classB: ClassB[];
}

在另一个class中,第一个class被用作外键:

@Entity({
  name: 'ClassB',
  database: Constants.DATABASE_NAME,
})
export class ClassB {

  ...

  @ManyToOne(() => ClassA, (classA) => classA.classB, {
    cascade: true,
  })
  @JoinColumn([
    { name: 'Field1', referencedColumnName: 'field1' },
    { name: 'Field2', referencedColumnName: 'field2' },
    { name: 'Field3', referencedColumnName: 'field3' },
  ])
  classA: ClassA;
}

当我使用 nest start 启动 NestJS 时,出现错误

code: "ER_FK_NO_INDEX_PARENT"
errno: 1822
sqlMessage: Failed to add the foreign key constraint. Missing index for constraint 'FK_1d19fe001872b5ee9ab545c18f8' in the referenced table 'ClassA'
sqlState: "HY000

我尝试修改ClassA table,在主键的每一列上添加索引,然后在主键的所有列上添加索引,但错误还是一样。

是否可以使用 TypeORM 来管理这种情况?

相关包:

数据库:MySQL v8.0 在 Docker 容器中 (mysql:latest)

谢谢。

编辑

问题似乎在于 table 是使用 TypeORM 在多个步骤中创建的。 table 在错误消息之后看起来像这样。

CREATE TABLE `ClassB` (
  `Date` datetime NOT NULL,
  `ClassAField1` varchar(4) NOT NULL,
  `ClassAField2` varchar(2) NOT NULL,
  `ClassAField3` int NOT NULL,
  PRIMARY KEY (`Date`,`ClassAField1`,`ClassAField2`,`ClassAField3`),
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci

错误发生在以下查询中,其中 TypeORM 尝试添加外键:

ALTER TABLE `ClassB`
ADD CONSTRAINT `FK_479eaf779e0d5f0d0a83bb9e30d`
FOREIGN KEY (`ClassAField1`, `ClassAField2`, `ClassAField3`)
REFERENCES `LandPlots`(`Field1`,`Field2`,`Field3`) ON DELETE NO ACTION ON UPDATE NO ACTION

我做了一些测试,下面的查询按预期工作:

CREATE TABLE `ClassB` (
  `Date` datetime NOT NULL,
  `ClassAField1` varchar(4) NOT NULL,
  `ClassAField2` varchar(2) NOT NULL,
  `ClassAField3` int NOT NULL,
  PRIMARY KEY (`Date`),
  KEY `FK_e6b2926df2c758d8d8810e4345a` (`ClassAField1`, `ClassAField2`, `ClassAField3`),
  CONSTRAINT `FK_e6b2926df2c758d8d8810e4345a`
  FOREIGN KEY (`ClassAField1`, `ClassAField2`, `ClassAField3`)
  REFERENCES `ClassA` (`Field1`, `Field2`, `Field3`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci

不同之处似乎是行 KEY `FK_e6b2926df2c758d8d8810e4345a` (`ClassAField1`, `ClassAField2`, `ClassAField3`),,它在 TypeORM 生成的 SQL 中缺失。

MySQL documentation 开始,KEY 语句与 INDEX:

同义
 KEY | INDEX

KEY is normally a synonym for INDEX. The key attribute PRIMARY KEY can also be specified as just KEY when given in a column definition. This was implemented for compatibility with other database systems. 

所以我尝试将 @Index 装饰器添加到列中,但它没有改变任何东西。我添加了所有已执行查询的日志记录,似乎 @Index 装饰器没有被执行,所以,也许 @JoinColumn 装饰器优先于它? (试图以不同的方式对装饰器进行排序以防万一)。

我能想到的使用 TypeORM 的唯一解决方案是生成所有 3 个主键的散列或串联,并使其成为唯一的主键。两个缺点:数据重复和 CPU 在插入前解析实体时的使用。

如果有人有更好的建议,我想听听。

编辑 @RickJames 提出的 2 个问题

更新语句:

UPDATE cb
SET cb.SomeField = 'NewValue'
FROM ClassB cb
JOIN ClassA ca
ON cb.Field1 = ca.Field1
AND cb.Field2 = ca.Field2
AND cb.Field3 = ca.Field3
WHERE ca.SomeOtherField LIKE '%partialvalue%'
AND cb.otherPK = 1

该 UPDATE 可能会受益于其中一些索引:

cb:  INDEX(otherPK, Field1, Field2, Field3)
ca:  INDEX(Field1, Field2, Field3, SomeOtherField)