NESTJS 中的 TypeORM 实体 - 不能在模块外部使用导入语句



使用"nest new"命令启动新项目。工作正常,直到我向其添加实体文件。

出现以下错误:

从 'typeorm' 导入 { Entity, Column, PrimaryGenerated Column }

;^^^^^^

语法错误:不能在模块外部使用导入语句

我错过了什么?

将实体添加到模块:

import { Module } from '@nestjs/common';
import { BooksController } from './books.controller';
import { BooksService } from './books.service';
import { BookEntity } from './book.entity';
import { TypeOrmModule } from '@nestjs/typeorm';
@Module({
imports: [TypeOrmModule.forFeature([BookEntity])],
controllers: [BooksController],
providers: [BooksService],
})
export class BooksModule {}

app.module.ts:

import { Module } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { TypeOrmModule } from '@nestjs/typeorm';
import { Connection } from 'typeorm';
import { BooksModule } from './books/books.module';
@Module({
imports: [TypeOrmModule.forRoot()],
controllers: [AppController],
providers: [AppService],
})
export class AppModule {}

我的假设是你有一个TypeormModule配置,其entities属性如下所示:

entities: ['src/**/*.entity.{ts,js}']

或喜欢

entities: ['../**/*.entity.{ts,js}']

您遇到的错误是因为您尝试在js上下文中导入ts文件。只要你不使用 webpack,你可以使用它来获得正确的文件

entities: [join(__dirname, '**', '*.entity.{ts,js}')]

其中joinpath模块导入。现在__dirname将解析为srcdist,然后分别找到预期的tsjs文件。如果仍有问题,请告诉我。

编辑1/10/2020

以上假设完成的配置是一个与javascript兼容的文件(.js或在TypeormModule.forRoot()传递的参数中)。如果您改用ormconfig.json,则应使用

entities: ["dist/**/*.entity.js"]

这样你正在使用编译的JS文件,并且没有机会在你的代码中使用TS文件。

在TypeORM文档中,我找到了Typescript的特定部分。

本节说:

全局安装 ts-node:

npm install -g ts-node

在 package.json 的脚本部分下添加 typeorm 命令

"scripts" {
...
"typeorm": "ts-node -r tsconfig-paths/register ./node_modules/typeorm/cli.js"    
}

然后你可以像这样运行命令:

npm run typeorm migration:run

如果需要将带有破折号的参数传递给 npm 脚本,则需要 在--.后添加它们例如,如果需要生成, 命令是这样的:

npm run typeorm migration:generate -- -n migrationNameHere

这适用于我的文件配置:

{
"type": "postgres",
"host": "yourhost",
"port": 5423,
"username": "username",
"password": "password",
"database": "your_db",
"synchronize": true,
"entities": [
"src/modules/**/*.entity.{ts,js}"
],
"migrations": [
"src/migrations/**/*.{ts,js}"
],
"cli": {
"entitiesDir": "src/modules",
"migrationsDir": "src/migrations"
}
}

然后,您可以运行生成命令。

正如Jay McDoniel在他的回答中所解释的那样,问题似乎是文件中实体文件的模式匹配ormconfig.json: 可能是打字稿文件(模块)是从javascript文件(可能是以前转译的打字稿文件)导入的。

删除ormconfig.json中现有的tsglob 模式就足够了,这样 TypeORM 将只加载 javascript 文件。实体文件的路径应相对于执行节点的工作目录。

"entities"   : [
"dist/entity/**/*.js"
],
"migrations" : [
"dist/migration/**/*.js"
],
"subscribers": [
"dist/subscriber/**/*.js"
],

接下来我在tsconfig.json文件中进行了更改:

"module": "es6"

自:

"module": "commonjs",

它帮助我

如官方文档中所述,在ormconfig.json中定义实体属性为我解决了这个问题。

// This is your ormconfig.json file
...
"entities": ["dist/**/*.entity{.ts,.js}"]
...

这就是我设法修复它的方式。使用单个配置文件,我可以在应用程序boostrap或使用TypeOrm的CLI上运行迁移。

src/config/ormconfig.ts

import parseBoolean from '@eturino/ts-parse-boolean';
import { TypeOrmModuleOptions } from '@nestjs/typeorm';
import * as dotenv from 'dotenv';
import { join } from 'path';
dotenv.config();
export = [
{
//name: 'default',
type: 'mssql',
host: process.env.DEFAULT_DB_HOST,
username: process.env.DEFAULT_DB_USERNAME,
password: process.env.DEFAULT_DB_PASSWORD,
database: process.env.DEFAULT_DB_NAME,
options: {
instanceName: process.env.DEFAULT_DB_INSTANCE,
enableArithAbort: false,
},
logging: parseBoolean(process.env.DEFAULT_DB_LOGGING),
dropSchema: false,
synchronize: false,
migrationsRun: parseBoolean(process.env.DEFAULT_DB_RUN_MIGRATIONS),
migrations: [join(__dirname, '..', 'model/migration/*.{ts,js}')],
cli: {
migrationsDir: 'src/model/migration',
},
entities: [
join(__dirname, '..', 'model/entity/default/**/*.entity.{ts,js}'),
],
} as TypeOrmModuleOptions,
{
name: 'other',
type: 'mssql',
host: process.env.OTHER_DB_HOST,
username: process.env.OTHER_DB_USERNAME,
password: process.env.OTHER_DB_PASSWORD,
database: process.env.OTHER_DB_NAME,
options: {
instanceName: process.env.OTHER_DB_INSTANCE,
enableArithAbort: false,
},
logging: parseBoolean(process.env.OTHER_DB_LOGGING),
dropSchema: false,
synchronize: false,
migrationsRun: false,
entities: [],
} as TypeOrmModuleOptions,
];

src/app.module.ts

import configuration from '@config/configuration';
import validationSchema from '@config/validation';
import { Module } from '@nestjs/common';
import { ConfigModule } from '@nestjs/config';
import { TypeOrmModule } from '@nestjs/typeorm';
import { LoggerService } from '@shared/logger/logger.service';
import { UsersModule } from '@user/user.module';
import { AppController } from './app.controller';
import ormconfig = require('./config/ormconfig'); //path mapping doesn't work here
@Module({
imports: [
ConfigModule.forRoot({
cache: true,
isGlobal: true,
validationSchema: validationSchema,
load: [configuration],
}),
TypeOrmModule.forRoot(ormconfig[0]), //default
TypeOrmModule.forRoot(ormconfig[1]), //other db
LoggerService,
UsersModule,
],
controllers: [AppController],
})
export class AppModule {}

包.json

"scripts": {
...
"typeorm": "ts-node -r tsconfig-paths/register ./node_modules/typeorm/cli.js --config ./src/config/ormconfig.ts",
"typeorm:migration:generate": "npm run typeorm -- migration:generate -n",
"typeorm:migration:run": "npm run typeorm -- migration:run"
},

项目结构

src/
├── app.controller.ts
├── app.module.ts
├── config
│   ├── configuration.ts
│   ├── ormconfig.ts
│   └── validation.ts
├── main.ts
├── model
│   ├── entity
│   ├── migration
│   └── repository
├── route
│   └── user
└── shared
└── logger

另请查看实体中的导入。不要import { SomeClassFromTypeorm } from 'typeorm/browser';,因为这可能会导致相同的错误。

在我的 IDE 自动导入错误的包后,它发生在我身上。从导入中删除'/browser'

当我遇到这个问题时,我正在使用带有Typescript和TypeORM的Node.js。在ormconfig.json文件中配置对我有用。

entities: ['dist/**/*.entity.js']

我的ormconfig.json文件的完整代码:

{
"type": "mysql",
"host": "localhost",
"port": 3306,
"username": "xxxxxxxx",
"password": "xxxxxxxx",
"database": "typescript_orm",
"synchronize": true,
"logging": false,
"migrationTableName": "migrations",
"entities": [
"dist/**/*.entity.js"
],
"migrations": [
"src/migration/**/*.{ts, js}"
],
"suscribers": [
"src/suscriber/**/*.{ts, js}"
],
"cli": {
"entitiesDir": "src/model",
"migrationDir": "src/migration",
"suscribersDir": "src/suscriber"
}
}

与其他人的评论一致 - 实际上,必须依赖生成的代码才能正常工作似乎很愚蠢。 我不认为这个解决方案是别人的仓库,但它实际上允许完整的仅 Typescript 迁移。 它依赖于.env文件 Typeorm 值而不是ormconfig.json尽管我确信它可以翻译。我发现它有助于帮助我消除对.js文件的依赖。

这是存储库: https://github.com/mthomps4/next-now-test/tree/next-typeorm-example

关于它是如何工作的解释:

除了通常的 .env 或 ormconfig.json 文件(其中包含正确的本地主机数据库连接)之外,您还需要在 ormconfig.json 或 .env 文件中正确指定以下内容

TYPEORM_ENTITIES="entities/*.ts"
TYPEORM_MIGRATIONS="migrations/*.ts"
TYPEORM_ENTITIES_DIR="entities"
TYPEORM_MIGRATIONS_DIR="migrations"

请注意,实体和迁移 glob 只有*.ts。 另一个非常重要的部分是如何设置 npm 脚本以与ts-node一起运行。

您需要一个扩展的 tsconfig,其中某处包含以下内容:

{
"extends": "./tsconfig.json",
"compilerOptions": {
"module": "commonjs"
}
}

这就是允许 ts-node 在生成迁移时正确"拾取".ts 文件的原因。

此 npm 脚本(DOTENV 部分仅在使用 .env 文件而不是ormconfig.json时)指定使用该tsconfig.json

"local": "DOTENV_CONFIG_PATH=./.env ts-node -P ./tsconfig.yarn.json -r dotenv/config"

它被用作"前光标"脚本:

"typeorm:local": "yarn local ./node_modules/typeorm/cli.js"

我不是 100% 确定所有这些都是必要的(你可以内联完成所有操作),但它对我有用。 基本上,这说的是"在具有特定 .env 文件和特定 tsconfig 的 ts-node 上下文中调用 typrorm cli"。 在某些情况下,您也许可以跳过这些配置。

最后,此脚本现在可以工作:

"g:migration": "yarn typeorm:local migration:generate -n"

因此,通过运行:

npm run g:migration -- User

您将获得基于当前更改的实体自动生成的迁移文件!

因此,在 3 个嵌套的 npm 脚本之后,我们有一种非常具体的方式来运行"生成"迁移 conmmand,并具有所有正确的配置以使用 TS 文件。 是的 - 难怪有些人仍然反对打字稿,但谢天谢地,这确实有效,如果你想尝试一下看看它是如何"工作"的,上面的示例存储库已经预配置了所有内容。

检查TypeOrmModule的实体

TypeOrmModule.forRoot({
type: 'postgres',
host: 'localhost',
port: 5432,
username: 'postgres',
password: '#GoHomeGota',
database: 'quiz',
**entities: ["dist/**/*.entity{.ts,.js}"],**
synchronize: true,
}),

<</div> div class="one_answers">我为此找到的替代方案是有两个orm配置文件 即orm-config.ts和cli-orm-config.ts(你可以给它们起任何名字)

//content of cli-orm-config.ts
import { DataSource, DataSourceOptions } from "typeorm"
import 'dotenv/config'
export const cliOrmConfig: DataSourceOptions = {
type: 'postgres',
host: process.env.DATABASE_HOST,
port: (process.env.PG_DATABASE_PORT as any) as number,
username: process.env.PG_DATABASE_USER,
password: process.env.PG_DATABASE_PASSWORD,
database: process.env.DATABASE_NAME,
entities: ["src/**/*/*.entity{.ts,.js}"],
migrations: ["src/**/*/*-Migration{.ts,.js}"]
}
const datasource = new DataSource(cliOrmConfig)
export default  datasource
//content of orm-config.ts, this is the one I use in nest TypeOrmModule.forRoot(ormConfig)
import { DataSource, DataSourceOptions } from 'typeorm';
import 'dotenv/config'

export const ormConfig: DataSourceOptions = {
type: 'postgres',
host: process.env.DATABASE_HOST,
port: (process.env.PG_DATABASE_PORT as any) as number,
username: process.env.PG_DATABASE_USER,
password: process.env.PG_DATABASE_PASSWORD,
database: process.env.DATABASE_NAME,
entities: ["dist/src/**/*/*.entity{.ts,.js}"]
}
const datasource = new DataSource(ormConfig)
export default  datasource
// My package.json relevant scripts section
"typeorm": "ts-node ./node_modules/typeorm/cli -d ./src/db/cli-orm-config.ts",
"nest:migration:generate": "npm run typeorm migration:generate ./src/db/migrations/Migration",
"nest:migration:run": "npm run typeorm migration:run"

我认为就TypeOrm而言,迁移,cli部分应该与模型加载和其他东西分开;因此,两者的orm配置文件是分开的。

希望它对某人有所帮助

实际上,typeorm 被设计为默认使用 javascript。

要使用打字稿运行迁移,您必须告诉 typeorm 执行此操作。

只需放入您的 package.json,在下面的脚本部分中

"typeorm": "ts-node-dev ./node_modules/typeorm/cli.js"

然后,尝试再次迁移:

yarn typeorm migration:run

我在尝试从使用 TypeORM 入门工具包 (npx typeorm init) 创建的项目运行typeorm migration:generate时遇到了此错误。问题归结为它插入package.json的这一位:

"scripts": {
"typeorm": "typeorm-ts-node-commonjs"
}

将其更改为:

"scripts": {
"typeorm": "typeorm-ts-node-esm"
}

你应该很高兴:

npm run -- typeorm migration:generate --dataSource path/to/data-source.ts NameOfMigration

对这些几乎有点笨拙的解决方案感到惊讶,尤其是在公认的解决方案中......

你永远不应该从 ts 源代码中的 dist 文件夹中导入任何东西!

如果回答的假设为真,并且您这样做:

entities: ['src/**/*.entity.{ts,js}']

那么,你为什么不宁愿这样做

import { Answer } from './entities/answer/answer.entity';
entities: [Answer]

这样你就可以(正确地)使用你的ts代码,并且构建的js代码将在运行时提供给TypeOrmModule。

你需要为应用的每个部分提供一个something.module.ts。 它的工作原理类似于角度。 这是使用 GraphQL 解析器和服务设置的。REST 与控制器有点不同。 每个模块可能都有一个实体,如果是 GraphQL,则为 projects.schema.graphql。

projects.module.ts

import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';
import { ProjectsService } from './projects.service';
import { Projects } from './projects.entity';
import { ProjectsResolvers } from './projects.resolvers';
@Module({
imports: [
TypeOrmModule.forFeature([Projects])],
providers: [
ProjectsService,
ProjectsResolvers
],
})
export class ProjectsModule {}

这对我有用 - 无需更改您的ormconfig.js.从node_modules所在的根目录运行:

ts-node ./node_modules/typeorm/cli.js  migration:generate -n <MirgrationName> -c <ConnectionType>

例:

ts-node ./node_modules/typeorm/cli.js  migration:create -n AuthorHasMultipleBooks -c development 

支持迁移的配置:

// FILE: src/config/ormconfig.ts
const connectionOptions: ConnectionOptions = {

// Other configs here
// My ormconfig isn't in root folder
entities: [`${__dirname}/../**/*.entity.{ts,js}`],
synchronize: false,
dropSchema: false,
migrationsRun: false,
migrations: [getMigrationDirectory()],
cli: {
migrationsDir: 'src/migrations',
}
}
function getMigrationDirectory() {
const directory = process.env.NODE_ENV === 'migration' ? 'src' : `${__dirname}`;
return `${directory}/migrations/**/*{.ts,.js}`;
}
export = connectionOptions;
// FILE package.json
{
// Other configs here
"scripts": {
"typeorm": "NODE_ENV=migration ts-node -r tsconfig-paths/register ./node_modules/typeorm/cli.js --config src/config/database.ts",
"typeorm:migrate": "npm run typeorm migration:generate -- -n",
"typeorm:run": "npm run typeorm migration:run",
"typeorm:revert": "npm run typeorm migration:revert"
}
}

我认为比公认的解决方案更好的解决方案是在您选择的 shell 中创建一个别名,该别名在node_modules中使用ts-node

注意:我使用 OhMyZsh 在 bash 中执行此操作,因此您的配置可能完全不同。

1:开放式外壳配置

开放式外壳配置1

nano ~/.zshrc

2:找到定义其他别名的位置并添加新别名

alias typeorm="ts-node ./node_modules/typeorm/cli.js"

3:关闭并保存

CTRL+X请求 nano 退出,按Y确认保存配置。

4:应用新配置

. ~/.zshrc

5:关闭终端并再次打开

您现在可以转到项目根目录并键入"typeorm",它将使用 ts-node 与node_modules中的 typeorm-cli 结合使用。

我遇到了同样的问题。唯一的区别是我的项目使用 .env 文件而不是 ormconfig.json

这就是我的 .env 文件配置的样子。

TYPEORM_ENTITIES = src/modules/*.entity.ts
TYPEORM_MIGRATIONS = src/migrations/*.entity.ts
TYPEORM_MIGRATIONS_RUN = src/migrations
TYPEORM_ENTITIES_DIR = src/modules
TYPEORM_MIGRATIONS_DIR = src/migrations

并使用命令运行

nest start

问题似乎是TypeORM不接受打字稿文件形式的实体。

有两种方法可用于解决此问题。

  1. 使用node-ts而不是nest start在不修改实体文件路径的情况下解决问题。据我了解,node-ts 将毫无问题地处理 src 文件夹中的打字稿文件。

  2. 更改实体和迁移文件路径,改为指向 dist 文件夹中已编译的 js 文件。

    TYPEORM_ENTITIES = dist/modules/*.entity.js
    TYPEORM_MIGRATIONS = dist/migrations/*.entity.js
    TYPEORM_MIGRATIONS_RUN = dist/migrations
    TYPEORM_ENTITIES_DIR = dist/modules
    TYPEORM_MIGRATIONS_DIR = dist/migrations
    

    通过这种方法,我可以毫无问题地使用nest start

我只将此解决方案用于生产。 对于开发,我将"../src/entity/**/*.ts"更改为"src/entity/**/*.ts",然后运行以下命令:"nodemon --exec ts-node ./src/index.ts"它有效 –

我解决了问题!

  1. 使用以下代码在根目录中创建pm2.config.js文件:

    module.exports = {
    apps: [
    {
    name: "app",
    script: "./build/index.js",
    },
    ],
    };
    
  2. 更改ormconfig.js中的实体路径

    {
    "type": "postgres",
    "host": "localhost",
    "port": 5432,
    "username": "postgres",
    "password": "password",
    "database": "db_name",
    "synchronize": false,
    "logging": true,
    "entities": [
    "../src/entity/**/*.ts",  ===>>> this line is important
    "./build/entity/**/*.js"
    ],
    "migrations": [
    "../src/migration/**/*.ts",===>>> this line is important
    "./build/migration/**/*.js"
    ],
    "subscribers": [
    "../src/subscriber/**/*.ts",===>>> this line is important
    "./build/subscriber/**/*.js"
    ],
    "cli": {
    "entitiesDir": "src/entity",
    "migrationsDir": "src/migration",
    "subscribersDir": "src/subscriber"
    }
    }
    
  3. 使用以下代码tsconfig.json

    {
    "compilerOptions": {
    "lib": [
    "es5",
    "es6"
    ],
    "target": "es5",
    "module": "commonjs",
    "moduleResolution": "node",
    "outDir": "./build",
    "emitDecoratorMetadata": true,
    "experimentalDecorators": true,
    "sourceMap": true,
    "esModuleInterop": true
    }
    }
    
  4. 为生产运行以下命令:

    tsc  =>> This command generate "build" folder
    
  5. pm2中运行节点应用程序运行以下命令:

    tsc && pm2 start pm2.config.js
    

现在,使用此解决方案2天后,我的应用程序与节点快速和typeorm一起工作! 此外,我的应用程序正在用pm2处理Linux和nginx。

这里接受的答案(https://stackoverflow.com/a/59607836/2040160)是帮助我生成和运行迁移,而不是运行NestJS项目。当我npm run start:dev时,我遇到了与作者相同的错误.

对我有用的是只在原版 JavaScript 中生成迁移文件。 我的ormconfig,json文件:

{ 
"type": "cockroachdb",
"host": "localhost",
"port": 26257,
"username": "root",
"password": "",
"database": "test",
"entities": ["dist/**/*.entity{.ts,.js}"],
"migrations": ["migration/*.js"],
"synchronize": false,
"cli": {
"migrationsDir": "migration"
}
}

package.json中的脚本:

"typeorm": "node --require ts-node/register ./node_modules/typeorm/cli.js"

以及我用来生成迁移的命令:

npm run typeorm migration:generate -- -o -n init

-o标志将以原版 JavaScript 输出迁移。

我将 NestJs 升级到 9.2.0,将 typeorm 升级到 0.3.10 我在运行新迁移时遇到了问题 但是我找到了对我有用的解决方案:

在以前的版本(nest 7 typeorm 0.2)中,我使用了以下命令:

npx ts-node ./node_modules/.bin/typeorm migration:generate -n MigrationName -d src/migrations 

更新后,我使用了此命令,它对我有用:

npx ts-node ./node_modules/.bin/typeorm migration:generate src/migration/MigrationName -d ormconfig.js

生成迁移时,我们需要设置新迁移的路径文件迁移:生成

-d 表示迁移目录 => -d src/migration intypeorm 0.2

-d 表示数据源 (config) => -d ormconfig intypeorm 0.3

如果您使用打字稿编写并使用tsc创建一个包含翻译的js文件的dist文件夹,那么您可能遇到我的问题,它将在这里得到解决。

正如文档中提到的,如果您使用nodemon server.js,那么您将从 js 的角度点击实体,它不会识别导入,因为它与 ts 和 es6 相关。但是,如果要从ts文件导入实体,则应运行ts-node server.ts

我个人认为前node server.js更安全,因为它更接近真实案例应用。

!!然而!!!请非常小心,因为如果您更改实体的名称,则必须删除dist文件夹并重建它,否则它将引发错误或意外工作。 发生错误是因为tsc将尝试翻译更改和创建的ts文件并保留已删除的文件,以便它可以更快地运行!

我希望它有所帮助,因为它肯定会在未来帮助我,因为我几乎可以肯定我会再次忘记它!

错误出在您的 ormconfig.json 文件上。 检查代码在哪里搜索实体、迁移、订阅者。在开发测试环境中,它将在 src/实体 src/migrations src/订阅者中搜索它们。但是在生产环境中,如果你保持原样,它仍然会搜索相同的路径,而不是你的构建路径dist/src/实体等;)。

我花了很多时间在这个迷你编译地狱:) 只需在 https://docs.nestjs.com/techniques/database 中使用自动加载实体选项

v有用!!

对我来说,在我的tsconfig.ts中更改模块 从

"module": "esnext"

自:

"module": "commonjs",

做了工作。

npm run typeorm migration:generate -- -n translationLength

最新更新