TypeORM OneToMany 导致“ReferenceError:在初始化之前无法访问'<Entity>'”

Posted

技术标签:

【中文标题】TypeORM OneToMany 导致“ReferenceError:在初始化之前无法访问\'<Entity>\'”【英文标题】:TypeORM OneToMany causes "ReferenceError: Cannot access '<Entity>' before initialization"TypeORM OneToMany 导致“ReferenceError:在初始化之前无法访问'<Entity>'” 【发布时间】:2020-06-07 08:11:48 【问题描述】:

我有两个实体:用户习惯。 一个用户可以创建多个习惯,因此我在用户上使用 OneToMany 关系(分别在习惯上使用 ManyToOne)。

用户实体

import Entity, PrimaryGeneratedColumn, Column, CreateDateColumn, UpdateDateColumn, BeforeInsert, BeforeUpdate, OneToMany from "typeorm";
import * as bcrypt from "bcryptjs";
import  Habit  from "../habits/habits.entity";

@Entity()
export class User 
    @PrimaryGeneratedColumn("uuid")
    id: string;

    @Column()
    name: string;

    @Column()
    email: string;

    @Column()
    password: string;

    @OneToMany(type => Habit, habit => habit.author)
    habits: Habit[];

    @CreateDateColumn()
    dateCreated: Date;

    @UpdateDateColumn()
    dateUpdated: Date;

    @BeforeInsert()
    @BeforeUpdate()
    async hashPassword(): Promise<void> 
        this.password = await bcrypt.hash(this.password,10);
    

    async comparePassword(password: string): Promise<boolean> 
        return bcrypt.compare(password, this.password);
    

    constructor(props: any) 
        Object.assign(this, props);
    

习惯实体

import Column, CreateDateColumn, Entity, PrimaryGeneratedColumn, UpdateDateColumn, ManyToOne from "typeorm";
import  User  from "../users/users.entity";

@Entity()
export class Habit 
    @PrimaryGeneratedColumn("uuid")
    id: string;

    @Column()
    name: string;

    @Column( nullable: true)
    description?: string;

    @ManyToOne(type => User, user => user.habits)
    author: User;

    @CreateDateColumn()
    dateCreated: Date;

    @UpdateDateColumn()
    dateUpdated: Date;

    constructor(props: Partial<Habit>) 
        Object.assign(this, props);
    

问题

在设置上述关系时,我收到以下错误

WARNING in Circular dependency detected:
apps\api\src\habits\habits.entity.ts -> apps\api\src\users\users.entity.ts -> apps\api\src\habits\habits.entity.ts

WARNING in Circular dependency detected:
apps\api\src\users\users.entity.ts -> apps\api\src\habits\habits.entity.ts -> apps\api\src\users\users.entity.ts


/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "User", function()  return User; );
                                                                                               ^
ReferenceError: Cannot access 'User' before initialization
    at Module.User (...\dist\apps\api\main.js:1782:96)
    at Module../apps/api/src/habits/habits.entity.ts (...\dist\apps\api\webpack:\apps\api\src\habits\habits.entity.ts:42:13)
    at __webpack_require__ (...\dist\apps\api\webpack:\webpack\bootstrap:19:1)
    at Module../apps/api/src/users/users.entity.ts (...\dist\apps\api\main.js:1790:79)
    at __webpack_require__ (...\dist\apps\api\webpack:\webpack\bootstrap:19:1)
    at Module../apps/api/src/config/db-config.service.ts (...\dist\apps\api\main.js:1038:77)
    at __webpack_require__ (...\dist\apps\api\webpack:\webpack\bootstrap:19:1)
    at Module../apps/api/src/config/config.module.ts (...\dist\apps\api\main.js:978:76)
    at __webpack_require__ (...\dist\apps\api\webpack:\webpack\bootstrap:19:1)
    at Module../apps/api/src/app/app.module.ts (...\dist\apps\api\main.js:147:79)

注意

我使用 Nx 并创建了一个 NestJS 应用。 TypeOrm 版本是 "^0.2.22",@nestjs/typeorm 版本是 "^6.2.0"

我的tsconfig如下:


  "compileOnSave": false,
  "compilerOptions": 
    "rootDir": ".",
    "sourceMap": true,
    "declaration": false,
    "moduleResolution": "node",
    "emitDecoratorMetadata": true,
    "experimentalDecorators": true,
    "importHelpers": true,
    "target": "es2015",
    "module": "esnext",
    "typeRoots": ["node_modules/@types"],
    "lib": ["es2018", "dom"],
    "skipLibCheck": true,
    "skipDefaultLibCheck": true,
    "baseUrl": ".",
    "paths": 
      "@awhile/contracts": ["libs/contracts/src/index.ts"],
      "@awhile/ui": ["libs/ui/src/index.ts"]
    
  ,
  "exclude": ["node_modules", "tmp"]

我尝试使用 ManyToMany 关系并且它有效。此外,在单独的 NestJS 应用程序(没有 Nx)上,我无法重现此参考错误。 在 tsconfig.json 中更改 ECMAScript target 版本也不起作用。

这两个实体仅在其服务中使用,不会在其他任何地方实例化。

感谢您的帮助。提前谢谢你。

【问题讨论】:

【参考方案1】:

您可以通过使用桶文件来完成与@jdruper 相同的事情。如果您的 tsconfig.json 中没有 paths 属性,请在 compilerOptions 下添加一个如下所示:

"paths": 
   "@entities":["app/src/entities/index.ts"]

将你所有的实体类放到entities文件夹中,创建index.ts文件,在index.ts文件中添加export语句:

export * from './user.entity';
export * from './habit.entity';

确保导出语句按要求的顺序出现。然后,您的导入将如下所示。

import  User, Habit  from '@entities';

您可以搜索 typescript bucket file 以了解有关如何使用桶文件的更多信息。

如果您使用的是 NX,您可以创建一个实体库并完成同样的事情。

这可能意味着必须将所有实体文件一起移动并更新模块和服务中的导入。也许不完全理想,但我更喜欢将它们全部放在一个文件中。

【讨论】:

如何让pathsts-loader 一起工作?【参考方案2】:

在 tsconfig 中,将目标设置为“esnext”并将模块设置为“commonjs”解决了我的问题


  "extends": "../../tsconfig.json",
  "compilerOptions": 
    "types": ["node", "jest"],
    "emitDecoratorMetadata": true,
    "experimentalDecorators": true,
    "module": "commonjs",
    "target": "esnext"
  ,
  "include": ["**/*.ts"]

【讨论】:

我试图让一个 vue 电子应用程序与 typeorm 一起工作。错误是:ReferenceError,在实体上声明之前不能使用变量。这对我有用。谢谢!【参考方案3】:

我在将 TypeORM 配置加载到 NestJS 时使用 autoLoadEntities: true 解决了这个问题。请注意,这是 NestJS 的额外内容,因此如果您使用 ormconfig.json,则不会应用此属性。

此处的 autoLoadEntities 文档:https://docs.nestjs.com/techniques/database#auto-load-entities

2020 年 4 月 10 日更新

我一直对关系有同样的问题。我发现的另一个解决方案,即使它违反了一些标准,也是将所有实体添加到一个文件中。在那里导出它们并在需要的地方导入它们。

请记住,声明类的顺序很重要。

【讨论】:

以上是关于TypeORM OneToMany 导致“ReferenceError:在初始化之前无法访问'<Entity>'”的主要内容,如果未能解决你的问题,请参考以下文章

在 find() 中 TypeORM 查询相关的 oneToMany 值

TypeORM 保存嵌套对象

在 TypeORM 和 NodeJS 中加入表

在 Typeorm 中引用实体的复合主键

NestJS & TypeORM:发布请求中的 DTO 格式

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