Nest.js 中的数据库操作

Jaxson Wang 编程技术 阅读量

安装 Typeorm

为了与 SQLNoSQL 数据库集成,Nest.js 提供了@nestjs/typeorm 软件包。Nest.js 使用 TypeORM,因为它是 TypeScript 最成熟的对象关系映射器(ORM)。由于它是用 TypeScript 编写的,因此可以与 Nest.js 框架很好地集成。

要开始使用它,先安装所需的依赖项:

npm install --save @nestjs/typeorm typeorm mysql2

本文数据库环境是 MySQL 8 下进行测试,依赖安装完成后在 AppModule(app.module.ts) 添加 TypeOrmModule 配置并且注入整个项目支持:

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

import { AppController } from './app.controller'
import { AppService } from './app.service'

@Module({
  imports: [
    TypeOrmModule.forRoot({
      type: 'mysql',
      host: 'localhost',
      port: 3306,
      username: 'root',
      password: '12345678',
      database: 'nest-demo1',
      entities: ['dist/**/*.entity.js'],
      synchronize: true
    })
  ],
  controllers: [AppController],
  providers: [AppService]
})
export class AppModule {
  constructor(private connection: Connection) {}
}

存储库模式

TypeORM支持存储库设计模式,每个实体都有自己的存储库。这些存储库可以从数据库连接中获取。例如创建一个 user 实体:

nest g module user

生成 user 文件夹后,新建个 user.entity.ts 实体:

import { Entity, Column, PrimaryColumn, BeforeInsert, CreateDateColumn, UpdateDateColumn } from 'typeorm'
import { v4 as uuidV4 } from 'uuid'

@Entity('app_user')
export class UserEntity {
  @PrimaryColumn({
    type: 'varchar',
    length: 36,
    nullable: false,
    comment: '用户编号'
  })
  id: string

  @BeforeInsert()
  updateId(): void {
    this.id = uuidV4()
  }

  @Column({
    type: 'varchar',
    length: 50,
    unique: true,
    comment: '用户名'
  })
  username: string

  @Column({
    type: 'varchar',
    length: 200,
    comment: '密码'
  })
  password: string

  @Column({
    type: 'varchar',
    length: 320,
    unique: true,
    comment: '邮箱'
  })
  email: string

  @Column({
    comment: '昵称'
  })
  nickname: string

  @Column({
    default: true,
    comment: '用户状态'
  })
  isActive: boolean

  @CreateDateColumn({
    type: 'timestamp',
    name: 'created_time',
    default: () => 'CURRENT_TIMESTAMP(6)',
    comment: '创建时间'
  })
  createdTime: Date

  @UpdateDateColumn({
    type: 'timestamp',
    name: 'updated_time',
    default: () => 'CURRENT_TIMESTAMP(6)',
    onUpdate: 'CURRENT_TIMESTAMP(6)',
    comment: '更新时间'
  })
  updatedTime: Date
}

上面涉及到各种名词请参考:TypeOrm文档,上面配置文件有个字段 entities: ['dist/**/*.entity.js'] 项目涉及所有的实体类命名风格都是这样,这样一来程序启动就会注册自己的实体。然后在 UsersModule 注册指定的实体类 user.module.ts

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

import { UserController } from './user.controller'
import { UserService } from './user.service'
import { UserEntity } from './user.entity'

@Module({
  imports: [TypeOrmModule.forFeature([UserEntity])],
  controllers: [UserController],
  providers: [UserService]
})
export class UserModule {}

然后下面进行编写 user 业务,打开 user.service.ts

import { Injectable } from '@nestjs/common'
import { InjectRepository } from '@nestjs/typeorm'
import { Repository } from 'typeorm'

import { UserEntity } from './user.entity'

@Injectable()
export class UserService {
  constructor(
    @InjectRepository(UserEntity)
    private userRepository: Repository<UserEntity>
  ) {}

  findAll(): Promise<UserEntity[]> {
    return this.userRepository.find()
  }

  findOne(id: string): Promise<UserEntity> {
    return this.userRepository.findOne(id)
  }

  async remove(id: string): Promise<void> {
    await this.userRepository.delete(id)
  }
}

创建好之后,下面进行编写控制器的路由来访问 user.controller.ts

import { Controller, Get, Post, Delete, Body, Param } from '@nestjs/common'

import { CreateUserDto } from './dto/create-user.dto'
import { UserEntity } from './user.entity'
import { UserService } from './user.service'

@Controller('user')
export class UserController {
  constructor(private readonly userService: UserService) {}

  @Post()
  create(@Body() createUserDto: CreateUserDto): Promise<UserEntity> {
    return this.userService.create(createUserDto)
  }

  @Get()
  findAll(): Promise<UserEntity[]> {
    return this.userService.findAll()
  }

  @Get(':id')
  findOne(@Param('id') id: string): Promise<UserEntity> {
    return this.userService.findOne(id)
  }

  @Delete(':id')
  remove(@Param('id') id: string): Promise<void> {
    return this.userService.remove(id)
  }
}

上面除了创建,其他都很好理解,都是根据 Orm 方法执行对应的方法,创建用户需要用到 DTO (Data Transfer Object) 创建的简单类模式来创建需要的对象,在 user 文件夹下新建个 dto 文件夹,创建 create-user.dto.ts

import { IsNotEmpty } from 'class-validator'

export class CreateUserDto {
  @IsNotEmpty()
  readonly username: string

  @IsNotEmpty()
  readonly password: string

  @IsNotEmpty()
  readonly email: string

  @IsNotEmpty()
  readonly nickname: string
}

创建好之后在 user.service.ts 添加 create() 方法:

create(createUserDto: CreateUserDto): Promise<UserEntity> {
  const user = new UserEntity()
  user.username = createUserDto.username
  user.password = createUserDto.password
  user.email = createUserDto.email
  user.nickname = createUserDto.nickname

  return this.userRepository.save(user)
}

class-validator 是实用的数据验证工具:npm i class-validator

1F5640377EFBE88848340046582AEB92

结语

上述代码数据库使用就是这样,不过细节上还有很多问题,比如新增用户要注意用户名的重复,删除需要验证等,这些后续再慢慢完善。

SunSeekerX 博主 “指指点点”

TypeOrm Docs

Nest.js Docs

本文案例源码:nest.js-typeorm-demo-1

喵~
Jaxson Wang
永远年轻,永远热泪盈眶!
Nest.js 环境变量配置和序列化
Nest.js 环境变量配置和序列化

程序在不同的环境下需要不同的环境变量,例如生产环境、测试环境以及开发环境所需要不同的数据库信息:链接地址、链接端口号、登录用户名和密码相关信息。为了解决这个问题需要进行相关操作。

3 分钟阅读
使用 Vue3 编写个管理后台 - 1
使用 Vue3 编写个管理后台 - 1

随着 Vue3 版本发布日渐成熟,Vue-Router 和 Vuex 从几个月的前的 Beta 版本迎来最近的正式版,再加上明年公司产品升级需要,最近开始尝试自己编写一套管理系统。

3 分钟阅读