Sequelize SQL

导读

本章仅适用于 TypeScript

警告 在本文中,您将学习如何使用自定义组件从头开始基于 Sequelize 包创建 DatabaseModule。因此,此技术包含大量开销,您可以通过使用专用的开箱即用的 @nestjs/sequelize 包来避免这些开销。要了解更多信息,请参阅 此处

Sequelize 是一种流行的对象关系映射器 (ORM),用原生 JavaScript 编写,但有一个 sequelize-typescript TypeScript 包装器,它为基础 sequelize 提供了一组装饰器和其他附加功能。

入门

要开始使用此库进行探索,我们必须安装以下依赖项:

bash
$ npm install --save sequelize sequelize-typescript mysql2
$ npm install --save-dev @types/sequelize

我们需要做的第一步是创建一个Sequelize实例,并将选项对象传递给构造函数。此外,我们需要添加所有模型(另一种方法是使用modelPaths属性)并sync()我们的数据库表。

database.providers
ts
import { Sequelize } from 'sequelize-typescript'
import { Cat } from '../cats/cat.entity'

export const databaseProviders = [
  {
    provide: 'SEQUELIZE',
    useFactory: async () => {
      const sequelize = new Sequelize({
        dialect: 'mysql',
        host: 'localhost',
        port: 3306,
        username: 'root',
        password: 'password',
        database: 'nest',
      })
      sequelize.addModels([Cat])
      await sequelize.sync()
      return sequelize
    },
  },
]
提示

按照最佳实践,我们在带有 *.providers.ts 后缀的分离文件中声明了自定义提供程序。

然后,我们需要导出这些提供程序,使它们可供应用程序的其余部分访问

ts
import { Module } from '@nestjs/common'
import { databaseProviders } from './database.providers'

@Module({
  providers: [...databaseProviders],
  exports: [...databaseProviders],
})
export class DatabaseModule {}

现在我们可以使用 @Inject() 装饰器注入 Sequelize 对象。每个依赖于 Sequelize 异步提供程序的类都将等待,直到 Promise 被解析。

模型注入

Sequelize 中,Model 定义数据库中的表。此类的实例表示数据库行。首先,我们需要至少一个实体:

cat.entity
ts
import { Column, Model, Table } from 'sequelize-typescript'

@Table
export class Cat extends Model {
  @Column
  name: string

  @Column
  age: number

  @Column
  breed: string
}

Cat 实体属于 cats 目录。此目录代表 CatsModule。现在是时候创建一个 Repository 提供程序了:

cats.providers
ts
import { Cat } from './cat.entity'

export const catsProviders = [
  {
    provide: 'CATS_REPOSITORY',
    useValue: Cat,
  },
]
警告

在实际应用中,您应该避免使用魔法字符串CATS_REPOSITORYSEQUELIZE 都应保存在单独的 constants.ts 文件中。

在 Sequelize 中,我们使用静态方法来操作数据,因此我们在这里创建了一个别名

现在我们可以使用 @Inject() 装饰器将 CATS_REPOSITORY 注入到 CatsService

cats.service
ts
import { Inject, Injectable } from '@nestjs/common'
import { CreateCatDto } from './dto/create-cat.dto'
import { Cat } from './cat.entity'

@Injectable()
export class CatsService {
  constructor(
    @Inject('CATS_REPOSITORY')
    private catsRepository: typeof Cat
  ) {}

  async findAll(): Promise<Cat[]> {
    return this.catsRepository.findAll<Cat>()
  }
}

数据库连接是异步的,但 Nest 使这个过程对最终用户完全不可见。CATS_REPOSITORY 提供程序正在等待数据库连接,而 CatsService 则被延迟,直到存储库准备好使用。当每个类被实例化时,整个应用程序就可以启动。

这是最终的 CatsModule

cats.module
ts
import { Module } from '@nestjs/common'
import { DatabaseModule } from '../database/database.module'
import { CatsController } from './cats.controller'
import { CatsService } from './cats.service'
import { catsProviders } from './cats.providers'

@Module({
  imports: [DatabaseModule],
  controllers: [CatsController],
  providers: [
    CatsService,
    ...catsProviders,
  ],
})
export class CatsModule {}
提示

不要忘记将CatsModule导入到根AppModule中。