TypeORM:如何在没有加载关系的属性的情况下显式设置 ForeignKey?

Posted

技术标签:

【中文标题】TypeORM:如何在没有加载关系的属性的情况下显式设置 ForeignKey?【英文标题】:TypeORM: How to set ForeignKey explicitly without having property for loading relations? 【发布时间】:2019-08-05 20:13:48 【问题描述】:

我不想创建用于将关系加载到其中的属性(如所有示例所示)。我唯一需要的是拥有一个显式外键属性,以便迁移 能够在数据库中为其创建适当的约束。最接近我需要的装饰器是@RelationId,但它仍然需要存在关系类的属性。

为了清楚起见,让我们以文档中的示例为例:

@Entity()
export class Post 
    @ManyToOne(type => Category)
    category: Category;

    @RelationId((post: Post) => post.category) // it still requires the presence of the `category` proeprty
    categoryId: number;


我在这里不需要category 属性。我想拥有categoryId 属性并将其标记为外键Category.Id。它应该是这样的:

@Entity()
export class Post 

    @ForeignKey((category: Category) => category.Id) // it's a foreign key to Category.Id
    categoryId: number;


有可能吗?

【问题讨论】:

嘿,你有办法解决这个问题吗? 对不起,伙计,我在一年前改变了我的技术栈。我相信我当时没有找到解决办法。 是的,我根据 charles 解决方案找到了它。 【参考方案1】:

“我需要的是有一个明确的外键属性”...

不,你不能。当你使用 @ManyToOne 装饰器时,TypeOrm 会自动创建外键属性。只需像这样将 @ManyToOne 和 @JoinColumn 装饰器组合在一起:

@ManyToOne(type => Category)
@JoinColumn( name: 'custom_field_name_if_you_want' )
category: Category;

【讨论】:

【参考方案2】:

也许您可以创建和编写自己的迁移并像这样使用它:

    const queryRunner = connection.createQueryRunner();
    await queryRunner.createTable(new Table(
        name: "question",
        columns: [
            
                name: "id",
                type: "int",
                isPrimary: true
            ,
            
                name: "name",
                type: "varchar",
            
        ]
    ), true);

    await queryRunner.createTable(new Table(
        name: "answer",
        columns: [
            
                name: "id",
                type: "int",
                isPrimary: true
            ,
            
                name: "name",
                type: "varchar",
            ,
            
                name: "questionId",
                isUnique: connection.driver instanceof CockroachDriver, // CockroachDB requires UNIQUE constraints on referenced columns
                type: "int",
            
        ]
    ), true);

    // clear sqls in memory to avoid removing tables when down queries executed.
    queryRunner.clearSqlMemory();

    const foreignKey = new TableForeignKey(
        columnNames: ["questionId"],
        referencedColumnNames: ["id"],
        referencedTableName: "question",
        onDelete: "CASCADE"
    );
    await queryRunner.createForeignKey("answer", foreignKey);

这段代码 sn-p 是从 orm 类型的functional test 中提取的,我认为您可以使用它在数据库上创建自己的约束。

【讨论】:

【参考方案3】:

其实是可以的:

@Entity()
export class Post 
    // this will add categoryId
    @ManyToOne(type => Category)
    category: Category;

    // and you can use this for accessing post.categoryId
    // only column you mark with @Column decorator will be mapped to a database column 
    // Ref: https://typeorm.io/#/entities
    categoryId: number;


添加的categoryId 不会映射到列,然后将用于显式设置 id 或访问其值,如下所示:

 post.categoryId = 1;
 // or 
 const id = post.categoryId

【讨论】:

【参考方案4】:

检查这两个地方 Auth module(JwtModule.register()) 和 JWT strategy(super(...))。确保您将秘密 /secretOrKey 设置为相同的密钥。就我而言,“secret:process.env.JWT_SECRET_KEY”和“secretOrKey:process.env.JWT_SECRET_KEY”

【讨论】:

嗨@Sunny Tare,记得使用块代码格式让你的代码在你的答案中更容易阅读【参考方案5】:

我最近遇到了同样的问题。 我仍然使用实体,但仅使用引用实体的主键值。

即我不查询被引用实体的数据库。

假设您的类别实体如下所示:

@Entity()
export class Category
    @PrimaryGeneratedColumn()
    id: number;

    // ... other stuff

现在以您的代码为例。 使用外键值直接分配关系就像。

// You wish to assign category #12 to a certain post
post.category =  id: 12  as Category

【讨论】:

以上是关于TypeORM:如何在没有加载关系的属性的情况下显式设置 ForeignKey?的主要内容,如果未能解决你的问题,请参考以下文章

typeORM 多对多关系不同情况的处理

在 TypeORM 与 GraphQL 的多对多关系上使用数据加载器,查询多对多

TypeORM postgresql 急切加载关系定义为惰性

TypeORM jsonb 数组列

如何在typeORM中保存@ManyToMany中的关系

如何创建如何在 typeorm 中创建多对多关系,[NestJS]