NestJs:从多个数据库查询多个实体

NestJs: Query multiple entities from multiple database

我有mysql_server_1.database1.users

和mysql_server_2.database3.users_revenue


首先,我已经设置了连接:

const mysql1__database1 = TypeOrmModule.forRootAsync({
  imports: [ConfigModule],
  // @ts-ignore
  useFactory: (configService: ConfigService) => ({
    type: configService.get("DASHBOARD_DB_TYPE"),
    host: configService.get("DASHBOARD_DB_HOST"),
    port: configService.get("DASHBOARD_DB_PORT"),
    username: configService.get("DASHBOARD_DB_USER"),
    password: configService.get("DASHBOARD_DB_PASSWORD"),
    database: configService.get("DASHBOARD_DB_NAME"),
    entities: [__dirname + '/**/*.entity{.ts,.js}'],
    // entities: [User],
    autoLoadEntities: true,
    synchronize: true,
  }),
  inject: [ConfigService],
});

const mysql2__database3 = TypeOrmModule.forRootAsync({
  imports: [ConfigModule],
  // @ts-ignore
  useFactory: (configService: ConfigService) => ({
    name: 'mysql2__database3',
    type: configService.get("DASHBOARD2_DB_TYPE"),
    host: configService.get("DASHBOARD2_DB_HOST"),
    port: configService.get("DASHBOARD2_DB_PORT"),
    username: configService.get("DASHBOARD2_DB_USER"),
    password: configService.get("DASHBOARD2_DB_PASSWORD"),
    database: configService.get("DASHBOARD2_DB_NAME"),
    entities: [__dirname + '/**/*.entity{.ts,.js}'],
    // entities: [User],
    autoLoadEntities: true,
    synchronize: true,
  }),
  inject: [ConfigService],
});

@Module({
  imports: [
    mysql1__database1,
    mysql2__database3,
    StatsModule,
  ],
  controllers: [AppController],
  providers: [AppService, StatsService],
})
export class AppModule {}

user.service.ts

import { Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { User } from './user.entity';

@Injectable()
export class UserService {
  constructor(@InjectRepository(User) private usersRepository: Repository<User>) {}

  async findAll(): Promise<User[]> {
    return await this.usersRepository.find();
  }
}

然后这段代码 return 我的数据库中存在一个空数组而不是这么多行;

const items = await this.userService.findAll();

---更新--- 我查看了 typeorm 源代码: https://github.com/nestjs/typeorm/blob/8af34889fa7bf14d7dc5541beef1d5c2b50c2609/lib/common/typeorm.decorators.ts#L13

然后https://docs.nestjs.com/techniques/database#multiple-databases

At this point, you have User and Album entities registered with their own connection. With this setup, you have to tell the TypeOrmModule.forFeature() method and the @InjectRepository() decorator which connection should be used. If you do not pass any connection name, the default connection is used.

所以我认为它应该有效?

@InjectRepository(User, 'mysql2_database3')
@Module({
  imports: [
    TypeOrmModule.forFeature([User], "mysql2_database3"),
  ],
  providers: [UserService],
  controllers: [StatsController],
})
export class StatsModule {}

仍然出现错误:

Please make sure that the argument mysql2_database3Connection at index [0] is available in the TypeOrmModule context.

感谢 @jmc29 在 discord 上,他的指导很有帮助

解决方法是:

const mysql2__database3 = TypeOrmModule.forRootAsync({
  imports: [ConfigModule],
  // @ts-ignore
  useFactory: (configService: ConfigService) => ({
    name: 'mysql2__database3',
    type: configService.get("DASHBOARD2_DB_TYPE"),
    host: configService.get("DASHBOARD2_DB_HOST"),
    port: configService.get("DASHBOARD2_DB_PORT"),
    username: configService.get("DASHBOARD2_DB_USER"),
    password: configService.get("DASHBOARD2_DB_PASSWORD"),
    database: configService.get("DASHBOARD2_DB_NAME"),
    entities: [__dirname + '/**/*.entity{.ts,.js}'],
    autoLoadEntities: true,
    synchronize: true,
  }),
  inject: [ConfigService],
});

再添加一行:

const mysql2__database3 = TypeOrmModule.forRootAsync({

  name: 'mysql2__database3', // -----> Add this line, it's is required

  imports: [ConfigModule],
  // @ts-ignore
  useFactory: (configService: ConfigService) => ({
    name: 'mysql2__database3',
    type: configService.get("DASHBOARD2_DB_TYPE"),
    host: configService.get("DASHBOARD2_DB_HOST"),
    port: configService.get("DASHBOARD2_DB_PORT"),
    username: configService.get("DASHBOARD2_DB_USER"),
    password: configService.get("DASHBOARD2_DB_PASSWORD"),
    database: configService.get("DASHBOARD2_DB_NAME"),
    entities: [__dirname + '/**/*.entity{.ts,.js}'],
    autoLoadEntities: true,
    synchronize: true,
  }),
  inject: [ConfigService],
});

对于遇到这个问题的人,这是我的解决方案

AppModule

@Module({
  imports: [
    ConfigModule.forRoot({
      isGlobal: true,
      load: [
        database,
        databaseAllo
      ]
    }),
    TypeOrmModule.forRootAsync({
      useFactory: (configs: ConfigService) => configs.get("db_config"),
      inject: [ConfigService],
    }),
    TypeOrmModule.forRootAsync({
      name:"db_allo", <= create connection to my second db
      useFactory: (configs: ConfigService) => configs.get("db_config_allo"),
      inject: [ConfigService],
    }),
    AuthModule,
    JwtAuthModule
  ],
  controllers: []
})
export class AppModule {}

我的项目模块(包含来自第二个数据库的 table)


@Module({
  imports: [
    TypeOrmModule.forFeature([AlloMpcTable], "db_allo" <= call connection again),
  ],
  providers: [
    AlloRepository
  ],
  exports: [AlloRepository],
  controllers: [],
})
export class AlloModule {}

我的项目库


@Injectable()
export class AlloRepository extends BaseRepository<AlloMpcTable> {
  constructor(
    @InjectRepository(AlloMpcTable, "db_allo") <= you need to call connection again
    private readonly allo: Repository<AlloMpcTable>,
  ) {
    super(allo)
  }

  public async Find(id: number): Promise<AlloMpcTable> {
    return await this.allo.findOne(id)
  }

}

所以在你的情况下,你需要在你的提供者中再次调用“mysql2_database3”:[UserService]