首页 > 解决方案 > TSyringe 和 TypeORM 在其他依赖项之前导入数据库依赖项

问题描述

我面临一个问题,其中我有很多存储库(它们是实现一个接口的 TS 类,它们是typeorm存储库类)并且我使用 TSyringe 来处理我的 API 中的所有依赖项

这是一个存储库的示例

import { getRepository, Repository } from 'typeorm';
import SafeUsd from '@modules/currencies/infra/typeorm/entities/SafeUsd';
import ICreateSafeUsdDTO from '@modules/currencies/dtos/ICreateSafeUsdDTO';
import ISafeUsdRepository from '@modules/currencies/repositories/ISafeUsdRepository';
import { classToClass } from 'class-transformer';
import IUpdateSafeUsdDTO from '@modules/currencies/dtos/IUpdateSafeUsdDTO';

export default class SafeUsdRepository implements ISafeUsdRepository {
  private ormRepository: Repository<SafeUsd>;

  constructor() {
    this.ormRepository = getRepository(SafeUsd);
  }

  async create(data: ICreateSafeUsdDTO): Promise<SafeUsd> {
    const safeUsd = this.ormRepository.create(data);

    await this.ormRepository.save(safeUsd);

    return classToClass(safeUsd);
  }

  async update({
    safeUsd,
    value,
    acceptable_variance,
    margin,
  }: IUpdateSafeUsdDTO): Promise<SafeUsd> {
    if (margin !== undefined) {
      safeUsd.margin = margin;
    }

    if (value !== undefined) {
      safeUsd.value = value;
    }

    if (acceptable_variance !== undefined) {
      safeUsd.acceptable_variance = acceptable_variance;
    }

    await this.ormRepository.save(safeUsd);

    return classToClass(safeUsd);
  }

  async findOne(): Promise<SafeUsd | undefined> {
    const safeUsd = await this.ormRepository.findOne();

    return classToClass(safeUsd);
  }
}

之后,我将所有存储库注册到一个文件中,在“shared/container/repositories/index.ts”中

import { container } from 'tsyringe';

import ICurrenciesRepository from '@modules/currencies/repositories/ICurrenciesRepository';
import CurrenciesRepository from '@modules/currencies/infra/typeorm/repositories/CurrenciesRepository';

import ICurrenciesUrlRepository from '@modules/currencies/repositories/ICurrenciesUrlRepository';
import CurrenciesUrlRepository from '@modules/currencies/infra/typeorm/repositories/CurrenciesUrlRepository';
import ISafeUsdRepository from '@modules/currencies/repositories/ISafeUsdRepository';
import SafeUsdRepository from '@modules/currencies/infra/typeorm/repositories/SafeUsdRepository';

container.registerSingleton<ICurrenciesRepository>(
  'CurrenciesRepository',
  CurrenciesRepository,
);

container.registerSingleton<ICurrenciesUrlRepository>(
  'CurrenciesUrlRepository',
  CurrenciesUrlRepository,
);

container.registerSingleton<ISafeUsdRepository>(
  'SafeUsdRepository',
  SafeUsdRepository,
);

在我的应用程序中,我也有一些提供程序(它们基本上是第三方 API 的实现,例如 AWS、GoogleFirebase 等......)

我想要做的是将我的一些存储库注入到我的提供程序中,然后我想注册它们由 TSyringe 容器解析的实例。

当我尝试做我刚刚在上面写的事情时,问题就开始了。在使用 TSyring 容器注册我的存储库和提供程序时,我会:

import './repositories';
import './providers';

它们都是执行 TSyringe container.registerSingleton、.resolve 或 .registerInstance 方法的大量 TS 文件。

我总是收到这个错误:

Error: Cannot inject the dependency at position #2 of "BitfinexBrokerProvider" constructor.
Reason:No repository for "Currency" was found. Looks like this entity is not registered in current "default" connection?

此错误意味着我的存储库尚未启动,因此当 TSyringe 尝试将它们注入我的提供程序时,它们尚未与数据库建立连接,因此我收到此错误。如果我不将这些存储库注入到我的提供程序中,那么一切正常。

关于如何解决这个问题的任何想法?我想做的是:

  1. 首先解析并注册所有存储库单例,以便它们与数据库连接。
  2. 只有在那之后,注册所有提供者。

关于如何做到这一点的任何想法?我希望我已经清楚地解决了我的问题,请问你们是否有任何疑问,我将编辑帖子以使其更清楚。

提前致谢。

更新:我尝试添加所有 TSyringe .registerSingleton() || .registerInstance() || .resolve(), 在一个 "setTimeout(() => {}, 3000)" 里面,它起作用了!正如我在问题中所说,我只需要稍等片刻,以便在我的存储库中建立数据库连接,然后再注入提供程序。

在这里你可以看到我做了什么

import { container } from 'tsyringe';

import BitfinexBrokerProvider from './implementations/BitfinexBrokerProvider';
import BrokerHandlerProvider from './implementations/BrokerHandlerProvider';
import FlowBTCBrokerProvider from './implementations/FlowBTCBrokerProvider';
import BitfinexChannelHandler from './implementations/websocket/bitfinex/ChannelHandler';

import IBrokerHandlerProvider from './models/IBrokerHandlerProvider';
import IBrokerProvider from './models/IBrokerProvider';
import IChannelHandler from './models/IChannelHandler';

setTimeout(() => {
  container.registerSingleton<IBrokerProvider>(
    'FlowBTCBrokerProvider',
    FlowBTCBrokerProvider,
  );

  container.registerSingleton<IChannelHandler>(
    'BitfinexChannelHandler',
    BitfinexChannelHandler,
  );

  const bitfinexBrokerProvider = container.resolve(BitfinexBrokerProvider);

  container.registerInstance<IBrokerProvider>(
    'BitfinexBrokerProvider',
    bitfinexBrokerProvider,
  );

  const brokerHandlerProvider = container.resolve(BrokerHandlerProvider);

  container.registerInstance<IBrokerHandlerProvider>(
    'BrokerProvider',
    brokerHandlerProvider,
  );
}, 3000);

虽然它有效,但我发现这个解决方案非常令人不快且不优雅。有没有更好的方法来实现更好的解决方案?

标签: typescriptsingletondomain-driven-designtypeormtsyringe

解决方案


您可以在 TSyringe 中使用“延迟”辅助函数。更多细节在这里

例子:

@injectable()
export class Foo {
  constructor(@inject(delay(() => Bar)) public bar: Bar) {}
}

@injectable()
export class Bar {
  constructor(@inject(delay(() => Foo)) public foo: Foo) {}
}

// construction of foo is possible
const foo = container.resolve(Foo);

// property bar will hold a proxy that looks and acts as a real Bar instance.
foo.bar instanceof Bar; // true

推荐阅读