简体   繁体   English

“ConnectionNotFoundError:未找到连接“默认””- class 属性

[英]"ConnectionNotFoundError: Connection "default" was not found" - class attribute

I'm learning NodeJS and the task is to build a simple messaging service.我正在学习 NodeJS,任务是构建一个简单的消息服务。 The teacher is using SQLite3, but I decided to use Postgres since it's the DB we use in our company projects.老师用的是SQLite3,但是我决定用Postgres,因为这是我们公司项目用的DB。

Error: "ConnectionNotFoundError: Connection "default" was not found"错误:“ConnectionNotFoundError:未找到连接“默认””

// server.ts

import 'reflect-metadata';
import express from 'express';
import { createConnection } from 'typeorm';

import router from './router';

(async () => {
  const PORT = 3333;

  console.log('before');
  await createConnection();
  console.log('after');

  const app = express();

  app.use(express.json());
  app.use(express.urlencoded({ extended: true }));

  app.use(router);

  app.listen(PORT, () => {
    console.log(`App is running on port ${PORT}`);
  });
})();

I have the following MessagesService我有以下MessagesService

// this works just fine
class MessagesService {
  async create({ user_id, text, admin_id }: MessagesCreateInterface): Promise<Message> {
    const repository = getCustomRepository(MessagesRepository);

    const message = repository.create({
      admin_id,
      text,
      user_id,
    });

    await repository.save(message);

    return message;
  }


  async listByUser(user_id: string): Promise<Array<Message>> {
    const repository = getCustomRepository(MessagesRepository);
    const messages = await repository.find({ user_id });
    return messages;
  }
}

Since getCustomRepository is called in both functions, and tried converting it to a class attribute:由于在两个函数中都调用了getCustomRepository ,并尝试将其转换为 class 属性:

class MessagesService {
  repository: MessagesRepository;

  constructor() {
    console.log('constructor');
    this.repository = getCustomRepository(MessagesRepository);
  }
  ...
}

But then I get ConnectionNotFoundError: Connection "default" was not found.但后来我得到ConnectionNotFoundError: Connection "default" was not found. . .

Experiments实验

  1. Using a setTimeout inside constructor : The connection is accessed.constructor中使用setTimeout :访问连接。

  2. Consoles.log: I get "before" and "constructor" print, but not "after". Consoles.log:我打印了“之前”和“构造函数”,但没有打印“之后”。

Can someone help me understand what's going on?有人可以帮助我了解发生了什么吗? As I'm using async/await, MessageService shouldn't be called until the connection was established.由于我正在使用异步/等待,因此在建立连接之前不应调用MessageService Am I'm breaking some pattern here?我在这里打破了一些模式吗?

You are not passing to TypeORM the connection options so it doesn't know how to connect and setup the connection (which is the default one).您没有将连接选项传递给 TypeORM,因此它不知道如何连接和设置连接(这是默认设置)。

Calling await createConnection() without parameters will load connection options from files and (as far as I can see) you have not any ormconfig.X file.不带参数调用await createConnection()将从文件加载连接选项,并且(据我所知)您没有任何ormconfig.X文件。

To pass connection options to TypeORM you have three options:要将连接选项传递给 TypeORM,您有三个选项:

  1. Connection Options Object连接选项对象
    See https://typeorm.io/#/connection .请参阅https://typeorm.io/#/connection
    Pass the connection options (object) directly when calling createConnection({ ... }) .调用createConnection({ ... })时直接传递连接选项(对象
    Example:例子:
const connection = await createConnection({
    type: "postgres",
    host: "localhost",
    port: 5432,
    username: "test",
    password: "test",
    database: "test"
});
  1. ormconfig.X file ormconfig.X 文件
    See https://typeorm.io/#/using-ormconfig .请参阅https://typeorm.io/#/using-ormconfig
    Load an ormconfig.[extension] file in the project root.在项目根目录中加载一个ormconfig.[extension]文件。
    Supported ormconfig file extensions are: .json, .js, .ts, .env, .yml and .xml.支持的 ormconfig 文件扩展名是:.json、.js、.ts、.env、.yml 和 .xml。
    Example (ormconfig.json):示例(ormconfig.json):
{
   "type": "postgres",
   "host": "localhost",
   "port": 5432,
   "username": "test",
   "password": "test",
   "database": "test"
}
  1. Environment variables环境变量
    See https://typeorm.io/#/using-ormconfig/using-environment-variables .请参阅https://typeorm.io/#/using-ormconfig/using-environment-variables
    TypeORM automatically searches connection options in the environment variables or in .env or ormconfig.env in the project root (near package.json). TypeORM 会自动在环境变量中或在项目根目录(package.json 附近)的.envormconfig.env中搜索连接选项。
    Example:例子:
TYPEORM_CONNECTION = postgres
TYPEORM_HOST = localhost
TYPEORM_PORT = 5432
TYPEORM_USERNAME = test
TYPEORM_PASSWORD = test
TYPEORM_DATABASE = test

The problem is that router.js is being imported before createConnection is called on server.ts .问题是在server.ts上调用createConnection之前正在导入router.js

Since the controllers are instantiated inside router.js , alongside the services and repositories, they were indeed trying to access a database connection before it was created.由于控制器在router.js内实例化,与服务和存储库一起,它们确实在创建之前尝试访问数据库连接。

The solution I found is to lazily import router.js after the connection has been established, but I'm not sure if that's an anti-pattern.我找到的解决方案是在建立连接后懒惰地导入router.js ,但我不确定这是否是一种反模式。

// server.ts

import 'reflect-metadata';
import express from 'express';
import { createConnection } from 'typeorm';

(async () => {
  await createConnection();
  // Importing routes after connection has been established
  const router = (await import('./router').default);
  const PORT = 3333;

  const app = express();

  app.use(express.json());
  app.use(express.urlencoded({ extended: true }));

  app.use(router);

  app.listen(PORT, () => {
    console.log(`App is running on port ${PORT}`);
  });
})();

The suggested way in the lectures was to create an instance of the controller inside every route, but it doesn't seem right to me.讲座中建议的方法是在每条路线内创建一个控制器实例,但这对我来说似乎不正确。

router.js

// suggested way
router.post('/messages', (request, response) => {
  const messagesController = new MessagesController();
  return messagesController.create(request, response); 
});

router.get('/messages/:id', (request, response) => {
  const messagesController = new MessagesController();
  return messagesController.showByUser(request, response); 
});

Since I'm still learning NodeJS, feel free to correct me and point me to the right way.由于我仍在学习 NodeJS,请随时纠正我并指出正确的方法。

I know that the question has been marked as answered, but I had a similar issue recently(related to unit tests with mocha).我知道这个问题已被标记为已回答,但我最近遇到了类似的问题(与 mocha 的单元测试有关)。 the solution, in my case, was to stub typeorm getCustomRepository :就我而言,解决方案是存根 typeorm getCustomRepository

import sinon from 'sinon';
import * as typeorm from 'typeorm';
import {Connection, ConnectionManager} from 'typeorm';

describe('groupService', () => {

    let getCustomRepositoryStub;

    beforeEach(() => {
        getCustomRepositoryStub = sinon.stub(typeorm, 'getCustomRepository');
        sinon.stub(ConnectionManager.prototype, 'get').returns({getCustomRepository: getCustomRepositoryStub} as  Connection);
    });

    afterEach(() => {
        sinon.restore();
    });

    it('findById returns empty result', async() => {
        const groupId: string = 'mock-group-id';
        getCustomRepositoryStub.withArgs(GroupRepository)
            .returns({
                findById: () => Promise.resolve([])
            });
        const groups = await groupService.getGroup(groupId);
        expect(groups.length).equal(0);
    });

    ...

});

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM