typescript - EntityMetadataNotFound: لم يتم العثور على أي بيانات وصفية لـ "BusinessApplication"


لقد كنت أستخدم TypeORM دون مشاكل لفترة من الوقت، لكن فجأة يظهر هذا الخطأ عند إجراء استدعاء API:

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)

يحدث هذا عندما يتم استدعاء هذا الكود:

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;

في 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';

في 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;

في 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;
}

من خلال ما أراه، جميع الاستيرادات تشير إلى الملف الصحيح، لقد استوردت reflect-metadata، ووضعّت المزخرف @Entity() على فئة BusinessApplication. فما الذي يمكن أن يكون خطأ؟ من الجدير بالذكر، إذا قمت بتغيير await manager.find(BusinessApplication, ...) في الملف الأول إلى await manager.find('BusinessApplication', ...) فإنه يعمل بشكل جيد، لكنني لا أريد القيام بذلك لأنني سأفقد ميزة الإكمال التلقائي (IntelliSense). أيضًا، هذا الخطأ لا يحدث عند تهيئة الخادم لأول مرة، ولكن بعد أن يتم إعادة تحميل الوحدة الساخنة (hot-module-reloaded) بواسطة Webpack، ينكسر (قد يحدث هذا بعد أن يتخلص Next.js من الصفحة أو بعد أن أغير الكود).

الإجابة رقم 1

المشكلة

بالنسبة لي، كان هذا يحدث بعد إعادة تحميل webpack الساخنة لأنه عند إعادة تحميل كل شيء، تم إنشاء نماذج كيان جديدة. على الرغم من إنشاء نماذج الكيان الجديدة، لم يكن TypeORM على علم بها لأنني قمت بعمل اتصال بقاعدة البيانات مرة واحدة فقط، عندما تم تهيئة وحدة database.ts، كما يمكنك أن ترى من الملف. لذلك عندما قارن TypeORM الكيانات الجديدة من استدعاء manager.find(BusinessApplication, ...) مع الكيانات القديمة، قال إنها ليست متطابقة لأنها لا تمتلك تساوي مرجعي (لا يوجد دالتان متطابقتان في JS). وبالتالي، لم يجد البيانات الوصفية عند مقارنتها مع manager.connection.entityMetadatas، التي احتوت على النسخة القديمة فقط.

الإصلاح

سأحتاج فقط إلى إنشاء اتصال جديد بقاعدة البيانات بعد كل إعادة تحميل بحيث يتم تزويدها ببيانات الكيان الجديدة.

الإجابة رقم 2

احذف مجلد dist من مشروعك وأعد التشغيل