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 来管理这种情况?
相关包:
- typeorm:
0.2.41
- @nestjs/core:
8.0.0
- @nestjs/typeorm:
8.0.3
- mysql:
2.18.1
数据库: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)
在第一个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 来管理这种情况?
相关包:
- typeorm:
0.2.41
- @nestjs/core:
8.0.0
- @nestjs/typeorm:
8.0.3
- mysql:
2.18.1
数据库: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)