nestjstypeormnode-oracledb

No metadata for Entity was found


Project informations:

Error log:

[Nest] 24652  - 16/05/2023 13:07:45   ERROR [ExceptionsHandler] No metadata for "Atendente" was found.
EntityMetadataNotFoundError: No metadata for "Atendente" was found.
{
  "statusCode": 500,
  "message": "Internal server error"
}

Others logs:

sei database using logging = true:
query: SELECT SYS_CONTEXT('USERENV','DB_NAME') AS "db_name" FROM dual
query: SELECT SYS_CONTEXT('USERENV','DB_NAME') AS "db_name" FROM dual

pad database using logging = true: 
query: SELECT SYS_CONTEXT('USERENV','CURRENT_SCHEMA') AS "schema_name" FROM dual
query: SELECT SYS_CONTEXT('USERENV','CURRENT_SCHEMA') AS "schema_name" FROM dual

Project Structure

https://docs.nestjs.com/techniques/database#multiple-databases
Following docs, I have a default db as sei.database.ts with no name given:

// src/database/sei.database.ts
import { TypeOrmModuleOptions } from '@nestjs/typeorm';

import * as dotenv from 'dotenv';
dotenv.config();

export const seiDatabase: TypeOrmModuleOptions = {
  type: 'oracle',
  host: process.env.SEI_CONNECTION_STRING_PROD,
  port: 1521,
  username: process.env.SEI_ORACLE_USER_PROD,
  password: process.env.SEI_ORACLE_PWD_PROD,
  sid: process.env.SEI_CONNECTION_SID_PROD,
  entities: [__dirname + '/../sei/**/*.entity{.ts,.js}'],
  synchronize: false,
  logging: true,
};

A second db named pad:

// /src/database/pad.database.ts
import { TypeOrmModuleOptions } from '@nestjs/typeorm';

import * as dotenv from 'dotenv';
dotenv.config();

export const padDatabase: TypeOrmModuleOptions = {
  name: 'pad',
  type: 'oracle',
  host: process.env.PAD_CONNECTION_STRING_PROD,
  port: 1521,
  username: process.env.PAD_ORACLE_USER_PROD,
  password: process.env.PAD_ORACLE_PWD_PROD,
  sid: process.env.PAD_CONNECTION_SID_PROD,
  entities: [__dirname + '/../pad/**/*.entity{.ts,.js}'],
  synchronize: false,
  logging: true,
};

On my app.module.ts:

// /src/app.module.ts
import { Module } from '@nestjs/common';

import { AppController } from './app.controller';
import { AppService } from './app.service';

import { DatabaseModule } from './database/database.module';

import { UsuariosModule } from './sei/usuarios/usuarios.module';

@Module({
  imports: [
    DatabaseModule,
    AtendentesModule,
    UsuariosModule,
  ],
  controllers: [AppController],
  providers: [AppService],
})
export class AppModule {}

my Atendente module atendentes.module.ts:

// /src/pad/atendentes.module.ts:
import { TypeOrmModule } from '@nestjs/typeorm';
import { Module } from '@nestjs/common';

import { AtendentesController } from './atendentes.controller';
import { AtendentesService } from './atendentes.service';
import { Atendente } from './entities/atendente.entity';

@Module({
  imports: [TypeOrmModule.forFeature([Atendente])],
  controllers: [AtendentesController],
  providers: [AtendentesService],
})
export class AtendentesModule {}

My Usuario module usuarios.module.ts:

// src/sei/usuarios.module.ts
import { TypeOrmModule } from '@nestjs/typeorm';
import { Module } from '@nestjs/common';

import { UsuariosController } from './usuarios.controller';
import { UsuariosService } from './usuarios.service';
import { Usuario } from './entities/usuario.entity';

@Module({
  imports: [TypeOrmModule.forFeature([Usuario])],
  controllers: [UsuariosController],
  providers: [UsuariosService],
})
export class UsuariosModule {}


My usuarios.module.ts is working because apparently it is pulling from the default data source, however, my atendentes.module.ts does not receive the connection because I could not set up the connection correctly and cannot find the error.

Update:
My connection is only being established on the database that is listed without the name (by default), if I change pad.database.ts and remove the name it connects (need to add a name property to sei.database.ts so that the file is ignored).


Solution

  • You need to specify the name of the data source as the second parameter when you register the entities in the forFeature method, unless is the default data source (the one without a name).

    // /src/pad/atendentes.module.ts:
    import { TypeOrmModule } from '@nestjs/typeorm';
    import { Module } from '@nestjs/common';
    
    import { AtendentesController } from './atendentes.controller';
    import { AtendentesService } from './atendentes.service';
    import { Atendente } from './entities/atendente.entity';
    
    @Module({
      imports: [TypeOrmModule.forFeature([Atendente], 'pad')],
      controllers: [AtendentesController],
      providers: [AtendentesService],
    })
    export class AtendentesModule {}
    

    Inside the service, it's needed to also pass the data source name to the InjectRepository decorator

    import { Injectable } from '@nestjs/common';
    import { InjectRepository } from '@nestjs/typeorm';
    import type { Repository } from 'typeorm';
    
    @Injectable()
    export class AtendentesService {
      constructor(@InjectRepository(Atendente, 'pad') private readonly repo: Repository<Atendente>) {}
    }