EntityMetadataNotFound: No metadata for "BusinessApplication" was found
Asked Answered
M

5

8

I've been using TypeORM with no problems for a while, but then suddenly this error pops up when making an API call:

EntityMetadataNotFound: No metadata for "BusinessApplication" was found.
    at new EntityMetadataNotFoundError (C:\Users\Robbie\Code\fit-society\node_modules\typeorm\error\EntityMetadataNotFoundError.js:10:28)
    at Connection.getMetadata (C:\Users\Robbie\Code\fit-society\node_modules\typeorm\connection\Connection.js:336:19)
    at EntityManager.<anonymous> (C:\Users\Robbie\Code\fit-society\node_modules\typeorm\entity-manager\EntityManager.js:459:44)
    at step (C:\Users\Robbie\Code\fit-society\node_modules\tslib\tslib.js:136:27)
    at Object.next (C:\Users\Robbie\Code\fit-society\node_modules\tslib\tslib.js:117:57)
    at C:\Users\Robbie\Code\fit-society\node_modules\tslib\tslib.js:110:75
    at new Promise (<anonymous>)
    at Object.__awaiter (C:\Users\Robbie\Code\fit-society\node_modules\tslib\tslib.js:106:16)
    at EntityManager.find (C:\Users\Robbie\Code\fit-society\node_modules\typeorm\entity-manager\EntityManager.js:456:24)
    at module.exports../src/pages/api/business-applications/[id].ts.__webpack_exports__.default.Object (C:\Users\Robbie\Code\fit-society\.next\server\static\development\pages\api\business-applications\[id].js:1648:65)
    at process._tickCallback (internal/process/next_tick.js:68:7)

It happens when this code is called:

import { BusinessApplication } from '../../../backend/all-entities';
import db from '../../../backend/database';

// in a function...
      const manager = await db.getManager();
      // in this case, req.data.id does equal "oldest"
      const application: BusinessApplication | undefined =
      req.data.id === 'oldest'
          ? (await manager.find(BusinessApplication, { order: { dateSubmitted: 'DESC' }, take: 1 }))[0]
          : await manager.findOne(BusinessApplication, { where: { id: parseInt(req.data.id, 10) } });
      if (application == null) throw createError(404, 'Business application not found');
      return application;

In backend/all-entities.ts:

/**
 * This file exists to solve circular dependency problems with Webpack by explicitly specifying the module loading order.
 * @see https://medium.com/visual-development/how-to-fix-nasty-circular-dependency-issues-once-and-for-all-in-javascript-typescript-a04c987cf0de
 */

import Account_ from './entities/Account';

export { default as Qualification } from './entities/Qualification';

export { default as EditableAccount } from './entities/EditableAccount';
export { default as EditableBusiness } from './entities/EditableBusiness';
export { default as Business } from './entities/Business';
export { default as BusinessApplication, SendableBusinessApplication } from './entities/BusinessApplication';
export { default as EditableCustomer } from './entities/EditableCustomer';
export { default as Customer } from './entities/Customer';

export { default as Offer } from './entities/Offer';
export { default as ProductOffer } from './entities/ProductOffer';
export { default as ServiceOffer } from './entities/ServiceOffer';

In backend/database.ts:

import 'reflect-metadata';
import {
  Connection,
  ConnectionManager,
  ConnectionOptions,
  createConnection,
  EntityManager,
  getConnectionManager
} from 'typeorm';
import { Business, BusinessApplication, Customer, ProductOffer, ServiceOffer, Qualification } from './all-entities';

/**
 * Database manager class
 */
class Database {
  private connectionManager: ConnectionManager;

  constructor() {
    this.connectionManager = getConnectionManager();
  }

  private async getConnection(): Promise<Connection> {
    const CONNECTION_NAME = 'default';
    let connection: Connection;

    if (this.connectionManager.has(CONNECTION_NAME)) {
      connection = this.connectionManager.get(CONNECTION_NAME);
      if (!connection.isConnected) {
        connection = await connection.connect();
      }
    } else {
      const connectionOptions: ConnectionOptions = {
        name: CONNECTION_NAME,
        type: 'postgres',
        url: process.env.DATABASE_URL,
        synchronize: true,
        entities: [Business, BusinessApplication, Qualification, Customer, ProductOffer, ServiceOffer]
      };
      connection = await createConnection(connectionOptions);
    }

    return connection;
  }

  public getManager(): Promise<EntityManager> {
    return this.getConnection().then(conn => conn.manager);
  }
}

const db = new Database();
export default db;

In backend/entities/BusinessApplication.ts:

import { IsIn, IsString, IsOptional } from 'class-validator';
import { Column, CreateDateColumn, Entity, PrimaryGeneratedColumn } from 'typeorm';
import { EditableBusiness } from '../all-entities';

class PasswordlessBusinessApplication extends EditableBusiness {
  @Column()
  @IsIn(['individual', 'company'])
  type!: 'individual' | 'company';

  @Column({ nullable: true })
  @IsOptional()
  @IsString()
  fein?: string;

  @Column({ nullable: true })
  @IsOptional()
  @IsString()
  professionalCertificationUrl?: string;
}

@Entity()
export default class BusinessApplication extends PasswordlessBusinessApplication {
  @PrimaryGeneratedColumn()
  id!: number;

  @CreateDateColumn()
  dateSubmitted!: Date;

  @Column()
  @IsString()
  passwordHash!: string;
}

/**
 * A business application sent by the client, which contains a password instead of a password hash.
 * Qualification objects do not require id or business.
 */
export class SendableBusinessApplication extends PasswordlessBusinessApplication {
  @IsString()
  password!: string;
}

From what I can see, the imports all point to the right file, I imported reflect-metadata, and I put the @Entity() decorator on the BusinessApplication class. So what could be going wrong? Notably, if I change await manager.find(BusinessApplication, ...) in the first file to await manager.find('BusinessApplication', ...) it works fine, but I don't want to do that because I'll lose intellisense. Also, this error doesn't happen the first time the server is initialized, but after it is hot-module-reloaded by Webpack it breaks (this can happen after Next.js disposes of the page or after I change the code).

Magnanimous answered 13/3, 2020 at 21:43 Comment(0)
M
8

The problem

For me, this was happening after the webpack hot-reload because when everything was reloaded, new entity models were generated. Although new entity models were generated, TypeORM didn't know about them because I only made a connection to the database once, when the database.ts module was initialized, as you can see from the file. So when TypeORM compared the new entities from the manager.find(BusinessApplication, ...) call and old entities, it said they were not the same because they don't have referential equality (no two functions are the same in JS). Therefore, it didn't find the metadata when comparing it to manager.connection.entityMetadatas, which contained the old version only.

The fix

I'll just need to make a new connection to the database after every reload so it is populated with the new entity metadata.

Magnanimous answered 14/3, 2020 at 16:57 Comment(2)
Can you please share the code snippets of the solution? or some more detail about the solution?Diastrophism
@AkshayPethani What specifically are you wondering? All that had to be done was create new connections with different (randomly generated in my case) names rather than "default" and close them manually.Magnanimous
P
2

remove dist folder from your project and run again

Paulinepauling answered 19/5, 2021 at 18:19 Comment(0)
H
2

Got this error when I renamed an entity without having .entity in the file name

Heterotrophic answered 6/8, 2021 at 14:37 Comment(0)
T
2

Don't forget to put entities into your DataSource (typeorm version 0.3.0 an above)

https://github.com/typeorm/typeorm/blob/master/CHANGELOG.md#030-2022-03-17

export const dataSource = new DataSource({
    ...
    ...
    entities: [BusinessApplication],
    ...
    ...
})
Testa answered 4/12, 2022 at 10:11 Comment(0)
M
0

After spending more time finally remove the dist folder from my project and run it.

It's worked

Marchall answered 13/12, 2022 at 6:14 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.