@nestjs/typeorm的使用

@nestjs/typeorm已经升级到了2.0版本,使用方法有些改变,重新写一次

lib/typeorm.module.ts

import { Module, DynamicModule, Global } from '@nestjs/common';
import { ConnectionOptions } from 'typeorm';

import { createTypeOrmProviders } from './typeorm.providers';
import { TypeOrmCoreModule } from './typeorm-core.module';

//默认装饰器中无数据,使用动态模块数据
@Module({})
export class TypeOrmModule {
  //静态方法,返回动态模块对象,参数为连接选项,提供了Connection、EntityManager组件
  static forRoot(options?: ConnectionOptions): DynamicModule {
    //这一步很搞笑,应该是写错了,因为providers压根没返回,而且这个方法就是个工具方法,没其他作用
    const providers = createTypeOrmProviders();
    //返回动态元数据对象
    return {
      //模块类
      module: TypeOrmModule,
      //关联模块,这里TypeOrmCoreModule.forRoot(options)也是得到一个动态元数据对象
      //里面包含了Connection、EntityManager组件
      modules: [TypeOrmCoreModule.forRoot(options)],
    };
  }

  //静态方法,参数为实体了,返回动态模块对象,提供了实体相应的Repository
  static forFeature(entities: Function[] = []): DynamicModule {
    //创建实体相应的Repository数组
    const providers = createTypeOrmProviders(entities);
    //返回动态元数据
    return {
      //模块类
      module: TypeOrmModule,
      //Repository组件数组
      components: providers,
      //Repository可导出,被注入使用此模块作为关联模块的组件中
      exports: providers,
    };
  }
}

可以看到:forRoot、forFeature两个方法都返回动态模块对象,而且其module属性都是TypeOrmModule,所以如果同时使用他们,其动态属性会被合并

也就是forRoot得到的modules属性会与forFeature得到的components、exports等属性合并到一个动态模块对象

可以推断出,在同一个模块中使用TypeormOrmModule,不管使用多少次,其得到的动态模块都会被合并为一个对象

如果在同一个项目中不同模块中使用TypeOrmModule,情况就复杂了



lib/typeorm-core.module.ts

import { Module, DynamicModule, Global } from '@nestjs/common';
import {
  ConnectionOptions,
  Connection,
  createConnection,
  EntityManager,
} from 'typeorm';

//核心模块,提供了Connection、EntityManager等组件
//注意!!!这是个全局模块,也就是项目中所有模块都会把它当作关联模块
//只有全局模块的组件才可以被不关联的模块注入
//其他情况下,要注入其他模块组件,必须关联该模块,且其组件必须导出
@Global()
@Module({})
export class TypeOrmCoreModule {
  //静态方法,根据连接选项返回动态模块
  static forRoot(options?: ConnectionOptions): DynamicModule {
    //Connection组件
    const connectionProvider = {
      //注意Inject使用的token只是Connection类
      provide: Connection,
      useFactory: async () => await createConnection(options),
    };
    //EntityManager组件
    const entityManagerProvider = {
      //token也是类
      provide: EntityManager,
      useFactory: (connection: Connection) => connection.manager,
      //注入了Connection
      inject: [Connection],
    };
    //返回动态元模块对象
    return {
      //模块类
      module: TypeOrmCoreModule,
      //组件
      components: [entityManagerProvider, connectionProvider],
      //组件可导出,因为这个组件要被Repository组件使用,所以它必须导出,而且它必须是全局模块,才能被不关联的模块使用
      exports: [entityManagerProvider, connectionProvider],
    };
  }
}

可以看到,TypeOrmCoreModule导出了Connection、EntityManager两个组件供外部使用,主要是供Repository组件使用

而且这个模块是全局模块,即不管其他模块与它关系如何,都可以注入其组件

那么问题很简单,如果使用两次TypeOrmMocule.forRoot,分别创建不同的连接,由于他们内部的Connection组件的注入token都是Connection,那么注入的时候会注入哪个Connection


lib/typeorm.providers.ts

import { ConnectionOptions, Connection } from 'typeorm';

import { getRepositoryToken } from './typeorm.utils';

//使用实体类创建相应的Repository组件
export function createTypeOrmProviders(entities?: Function[]) {
  //从Connection获取Repository的方法
  const getRepository = (connection: Connection, entity) =>
    connection.options.type === 'mongodb'
      ? connection.getMongoRepository(entity)
      : connection.getRepository(entity);

  //Repository组件数组
  //遍历实体
  const repositories = (entities || []).map(entity => ({
    //获取token
    provide: getRepositoryToken(entity),
    useFactory: (connection: Connection) =>
      getRepository(connection, entity) as any,
    //注入Connection
    inject: [Connection],
  }));
  return [...repositories];
}
说明TypeOrmModule.forFeature方法是依赖于forRoot方法的,只有先获取Connection,才能获取Repository

lib/typeorm.util.ts

export function getRepositoryToken(entity: Function) {
  return `${entity.name}Repository`;
}
Repository组件的token就是给前面加上了实体类的名称,这也是可能重复的


lib/typeorm.decorators.ts

import { Inject } from '@nestjs/common';

import { getRepositoryToken } from './typeorm.utils';

export const InjectRepository = (entity: Function) =>
  Inject(getRepositoryToken(entity));

InjectRepository只是封装了Inject,并且注入内部约定好的token


总的来说,使用TypeOrmModule模块最大的问题是不能出现两个数据库连接,不然注入的Connection会乱,如果要使用多个数据库,还是自己写provider比较好





你可能感兴趣的:(nest.js)