@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得到的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));
总的来说,使用TypeOrmModule模块最大的问题是不能出现两个数据库连接,不然注入的Connection会乱,如果要使用多个数据库,还是自己写provider比较好