NestJS TypeORM集成 #

TypeORM简介 #

TypeORM是一个支持TypeScript的ORM框架,可以运行在Node.js、浏览器、Cordova、PhoneGap等平台上。它支持多种数据库,包括MySQL、PostgreSQL、MariaDB、SQLite、MS SQL Server等。

安装依赖 #

bash
npm install @nestjs/typeorm typeorm mysql2
# 或 PostgreSQL
npm install @nestjs/typeorm typeorm pg
# 或 SQLite
npm install @nestjs/typeorm typeorm better-sqlite3

配置TypeORM #

使用forRoot配置 #

typescript
import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';

@Module({
  imports: [
    TypeOrmModule.forRoot({
      type: 'mysql',
      host: 'localhost',
      port: 3306,
      username: 'root',
      password: 'password',
      database: 'test',
      entities: [],
      synchronize: true,
    }),
  ],
})
export class AppModule {}

使用环境变量 #

typescript
import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';
import { ConfigModule, ConfigService } from '@nestjs/config';

@Module({
  imports: [
    ConfigModule.forRoot(),
    TypeOrmModule.forRootAsync({
      imports: [ConfigModule],
      useFactory: (configService: ConfigService) => ({
        type: 'mysql',
        host: configService.get('DB_HOST'),
        port: configService.get('DB_PORT'),
        username: configService.get('DB_USERNAME'),
        password: configService.get('DB_PASSWORD'),
        database: configService.get('DB_DATABASE'),
        entities: [__dirname + '/**/*.entity{.ts,.js}'],
        synchronize: configService.get('NODE_ENV') !== 'production',
      }),
      inject: [ConfigService],
    }),
  ],
})
export class AppModule {}

配置选项 #

选项 说明
type 数据库类型
host 数据库主机
port 数据库端口
username 用户名
password 密码
database 数据库名
entities 实体类
synchronize 自动同步表结构
logging 日志级别

定义实体 #

基本实体 #

typescript
import { Entity, Column, PrimaryGeneratedColumn } from 'typeorm';

@Entity('users')
export class User {
  @PrimaryGeneratedColumn()
  id: number;

  @Column()
  name: string;

  @Column({ unique: true })
  email: string;

  @Column({ select: false })
  password: string;

  @Column({ default: true })
  isActive: boolean;

  @Column({ type: 'text', nullable: true })
  bio: string;

  @Column({ type: 'datetime', default: () => 'CURRENT_TIMESTAMP' })
  createdAt: Date;

  @Column({ type: 'datetime', nullable: true })
  updatedAt: Date;
}

列装饰器 #

装饰器 说明
@PrimaryGeneratedColumn() 自增主键
@PrimaryColumn() 自定义主键
@Column() 普通列
@CreateDateColumn() 创建时间
@UpdateDateColumn() 更新时间
@DeleteDateColumn() 软删除时间
@VersionColumn() 版本号

列选项 #

typescript
@Column({
  type: 'varchar',
  length: 100,
  nullable: false,
  unique: true,
  default: 'default value',
  select: false,
  comment: '用户邮箱',
})
email: string;

实体关系 #

一对一关系 #

typescript
import { Entity, PrimaryGeneratedColumn, Column, OneToOne, JoinColumn } from 'typeorm';

@Entity()
export class User {
  @PrimaryGeneratedColumn()
  id: number;

  @Column()
  name: string;

  @OneToOne(() => Profile, profile => profile.user)
  @JoinColumn()
  profile: Profile;
}

@Entity()
export class Profile {
  @PrimaryGeneratedColumn()
  id: number;

  @Column()
  avatar: string;

  @OneToOne(() => User, user => user.profile)
  user: User;
}

一对多关系 #

typescript
import { Entity, PrimaryGeneratedColumn, Column, OneToMany, ManyToOne } from 'typeorm';

@Entity()
export class User {
  @PrimaryGeneratedColumn()
  id: number;

  @Column()
  name: string;

  @OneToMany(() => Post, post => post.author)
  posts: Post[];
}

@Entity()
export class Post {
  @PrimaryGeneratedColumn()
  id: number;

  @Column()
  title: string;

  @ManyToOne(() => User, user => user.posts)
  author: User;
}

多对多关系 #

typescript
import { Entity, PrimaryGeneratedColumn, Column, ManyToMany, JoinTable } from 'typeorm';

@Entity()
export class User {
  @PrimaryGeneratedColumn()
  id: number;

  @ManyToMany(() => Role, role => role.users)
  @JoinTable()
  roles: Role[];
}

@Entity()
export class Role {
  @PrimaryGeneratedColumn()
  id: number;

  @Column()
  name: string;

  @ManyToMany(() => User, user => user.roles)
  users: User[];
}

仓库模式 #

注册实体 #

typescript
import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';
import { User } from './entities/user.entity';
import { UsersService } from './users.service';
import { UsersController } from './users.controller';

@Module({
  imports: [TypeOrmModule.forFeature([User])],
  controllers: [UsersController],
  providers: [UsersService],
})
export class UsersModule {}

使用Repository #

typescript
import { Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { User } from './entities/user.entity';

@Injectable()
export class UsersService {
  constructor(
    @InjectRepository(User)
    private usersRepository: Repository<User>,
  ) {}

  findAll(): Promise<User[]> {
    return this.usersRepository.find();
  }

  findOne(id: number): Promise<User | null> {
    return this.usersRepository.findOne({ where: { id } });
  }

  findByEmail(email: string): Promise<User | null> {
    return this.usersRepository.findOne({ where: { email } });
  }

  async create(userData: Partial<User>): Promise<User> {
    const user = this.usersRepository.create(userData);
    return this.usersRepository.save(user);
  }

  async update(id: number, userData: Partial<User>): Promise<User | null> {
    await this.usersRepository.update(id, userData);
    return this.findOne(id);
  }

  async remove(id: number): Promise<void> {
    await this.usersRepository.delete(id);
  }
}

查询构建器 #

基本查询 #

typescript
const users = await this.usersRepository
  .createQueryBuilder('user')
  .where('user.isActive = :isActive', { isActive: true })
  .orderBy('user.createdAt', 'DESC')
  .getMany();

关联查询 #

typescript
const user = await this.usersRepository
  .createQueryBuilder('user')
  .leftJoinAndSelect('user.posts', 'post')
  .leftJoinAndSelect('post.comments', 'comment')
  .where('user.id = :id', { id: 1 })
  .getOne();

分页查询 #

typescript
async findWithPagination(page: number, limit: number) {
  const [data, total] = await this.usersRepository
    .createQueryBuilder('user')
    .skip((page - 1) * limit)
    .take(limit)
    .getManyAndCount();

  return {
    data,
    total,
    page,
    limit,
    totalPages: Math.ceil(total / limit),
  };
}

复杂查询 #

typescript
const users = await this.usersRepository
  .createQueryBuilder('user')
  .select(['user.id', 'user.name', 'user.email'])
  .where('user.isActive = :isActive', { isActive: true })
  .andWhere(
    new Brackets(qb => {
      qb.where('user.name LIKE :name', { name: '%John%' })
        .orWhere('user.email LIKE :email', { email: '%@example.com%' });
    }),
  )
  .orderBy('user.createdAt', 'DESC')
  .getMany();

事务处理 #

使用@Transaction装饰器(已弃用) #

使用DataSource #

typescript
import { Injectable } from '@nestjs/common';
import { DataSource } from 'typeorm';
import { User } from './entities/user.entity';

@Injectable()
export class UsersService {
  constructor(private dataSource: DataSource) {}

  async createWithTransaction(userData: any) {
    const queryRunner = this.dataSource.createQueryRunner();
    await queryRunner.connect();
    await queryRunner.startTransaction();

    try {
      const user = queryRunner.manager.create(User, userData);
      await queryRunner.manager.save(user);

      // 其他操作...

      await queryRunner.commitTransaction();
      return user;
    } catch (error) {
      await queryRunner.rollbackTransaction();
      throw error;
    } finally {
      await queryRunner.release();
    }
  }
}

使用EntityManager.transaction #

typescript
await this.dataSource.transaction(async manager => {
  const user = manager.create(User, userData);
  await manager.save(user);

  const profile = manager.create(Profile, profileData);
  await manager.save(profile);
});

数据库迁移 #

创建迁移文件 #

bash
npm run typeorm migration:create -- -n CreateUserTable

迁移文件示例 #

typescript
import { MigrationInterface, QueryRunner, Table } from 'typeorm';

export class CreateUserTable1700000000000 implements MigrationInterface {
  public async up(queryRunner: QueryRunner): Promise<void> {
    await queryRunner.createTable(
      new Table({
        name: 'users',
        columns: [
          {
            name: 'id',
            type: 'int',
            isPrimary: true,
            isGenerated: true,
            generationStrategy: 'increment',
          },
          {
            name: 'name',
            type: 'varchar',
            length: '100',
          },
          {
            name: 'email',
            type: 'varchar',
            length: '100',
            isUnique: true,
          },
          {
            name: 'createdAt',
            type: 'datetime',
            default: 'CURRENT_TIMESTAMP',
          },
        ],
      }),
    );
  }

  public async down(queryRunner: QueryRunner): Promise<void> {
    await queryRunner.dropTable('users');
  }
}

运行迁移 #

bash
npm run typeorm migration:run
npm run typeorm migration:revert

自定义仓库 #

typescript
import { EntityRepository, Repository } from 'typeorm';
import { User } from './entities/user.entity';

@EntityRepository(User)
export class UsersRepository extends Repository<User> {
  findActiveUsers(): Promise<User[]> {
    return this.createQueryBuilder('user')
      .where('user.isActive = :isActive', { isActive: true })
      .getMany();
  }

  findByRole(role: string): Promise<User[]> {
    return this.createQueryBuilder('user')
      .innerJoin('user.roles', 'role')
      .where('role.name = :role', { role })
      .getMany();
  }
}

总结 #

本章学习了NestJS与TypeORM的集成:

  • TypeORM配置
  • 实体定义
  • 实体关系
  • 仓库模式
  • 查询构建器
  • 事务处理
  • 数据库迁移

接下来,让我们学习 Prisma集成

最后更新:2026-03-28