当前位置: 首页 > 工具软件 > nestjs-query > 使用案例 >

Nodejs之NestJS之TypeORM使用

万俟经纶
2023-12-01

Nodejs之NestJS之TypeORM使用

node下的TypeORM比上不足,比下有余,这里分享一些使用经验

一、入口

TypeORM提供的入口很多,connection,entityManager,repo,使用的时候难免纠结用什么,这里建议统一使用entityManager:

getManager()

二、事务

建议封装事务,动态传入entityManager,方便复用和测试:

import { EntityManager, getManager } from 'typeorm';
import { IsolationLevel } from 'typeorm/driver/types/IsolationLevel';

export const runInTransaction = async (callback: any, options?: any) => {
  const connectionName = options?.connectionName ?? 'default';
  const isolationLevel: IsolationLevel | undefined = options?.isolationLevel;
  if (!options?.entityManager) {
    await getManager(connectionName).transaction(
      isolationLevel,
      async (entityManager: EntityManager) => await callback(entityManager),
    );
  } else {
    await callback(options?.entityManager);
  }
};

三、数据库连接

在NestJS下,我们默认在app.module.ts里配置连接:

    TypeOrmModule.forRootAsync({
      useFactory: async (config: ConfigService) => config.get('database'),
      inject: [ConfigService],
    }),

有的时候我们想要自己控制连接,比如允许数据库连接失败,这时候就需要换一种方式:

  1. 初始化:主动触发createConnection并允许失败

    import { Injectable, OnApplicationBootstrap } from '@nestjs/common';
    import { ConfigService } from '@nestjs/config';
    import { ConnectionOptions, createConnection } from 'typeorm';
    
    @Injectable()
    export class AppService implements OnApplicationBootstrap {
      constructor(
        private readonly config: ConfigService,
      ) {}
      async onApplicationBootstrap() {
        try {
          await createConnection(this.config.get<ConnectionOptions>('database'));
        } catch (error) {}
      }
    }
    
  2. 获取连接

    export const getCustomConnection = async (connectionName?: string) => {
      let connection = getConnection(connectionName ?? 'default');
      // 防止初始化时连接失败
      if (!connection.isConnected) {
        await connection.connect();
      };
      return connection;
    };
    

四、测试

建议使用真实数据库,通过事务管理测试:

describe('TestService', () => {
  let repository: Repository<Test>;
  let service: TestService;
  let connection: Connection;
  let queryRunner: QueryRunner;
  beforeAll(async () => {
    // 超时
    jest.setTimeout(1000 * 60);

    // 使用Nest方式注入
    const moduleRef = await Test.createTestingModule({
      imports: [
        ConfigModule.forRoot({
          load: appConfig,
          isGlobal: true,
        }),
        TypeOrmModule.forRoot(TypeOrmTestConfig)
      ],
    }).compile();

    // 创建queryRunner
    connection = getConnection();
    queryRunner = connection.createQueryRunner();
    await queryRunner.connect();

    let configService = moduleRef.get<ConfigService>(ConfigService);
    repository = queryRunner.manager.getRepository(Test);
    service = new TestService(
      repository,
      configService,
    );
  });

  beforeEach(async () => {
    // 开启事务
    await queryRunner.startTransaction();
  });

  afterEach(async () => {
    // 回滚事务
    await queryRunner.rollbackTransaction();
  });

  afterAll(async () => {
    // 释放queryRunner
    await queryRunner.release();
  });

  it('test', async () => {
    const test = await queryRunner.manager.findOne(Test, 1);
    expect(test).not.toBeUndefined();
  });
});

五、其他

  • 避免使用em.save,单独使用em.insertem.update

  • 生产环境禁止启用synchronize,使用migrationsRun

  • sqlserver因为node的问题,要配置options: {encrypt: false}

 类似资料: