【发布时间】:2023-03-15 11:17:01
【问题描述】:
在第一类中,主键是复合的:
@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[];
}
在另一个类中,第一个类用作外键:
@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表,在主键的每一列上添加索引,然后对主键的所有列进行索引,但错误还是一样。
是否可以使用 TypeORM 管理这种情况?
相关包:
- typeorm:
0.2.41 - @nestjs/核心:
8.0.0 - @nestjs/typeorm:
8.0.3 - mysql:
2.18.1
数据库:MySQL v8.0 在 Docker 容器中 (mysql:latest)
谢谢。
编辑
似乎问题在于使用 TypeORM 不止一步创建了表。错误消息后的表格如下所示。
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
【问题讨论】:
-
在帮助 how to 索引之前,我想先评论一下 what to 索引。请提供您希望为其添加索引的示例
SELECTs/UPDATEs/DELETEs`。 -
你好@RickJames。复合外键上的索引(第 6 个代码 sn-p 中的“KEY”),否则,根据我的测试,它最终可以工作。但是TypeORM似乎并没有同时处理主键+ \@ManyToOne + \@JoinColumn + \@Index,它只处理PK,然后尝试将列更改为复合FK,这不起作用。我添加了一条更新声明,但我不确定我是否很好地理解了您的问题。
-
<frustration>我的太多时间都花在尝试解决产品(ORM 等)中试图对用户隐藏 MySQL 的缺陷上。用户最终不得不理解 both 抽象并编写“原始”查询以获得性能。</frustration> -
@RickJames 我同意你的看法。对于简单的操作,ORM 很酷,而且我还想通过不操作 SQL 来使流程更干净,但最终一项需要几个小时的工作却占用了我个人的几天时间。
标签: mysql typescript nestjs typeorm