本章仅适用于 TypeScript
警告 在本文中,您将学习如何使用自定义提供程序机制从头开始基于 TypeORM 包创建
DatabaseModule
。因此,此解决方案包含大量开销,您可以使用现成的、开箱即用的专用@nestjs/typeorm
包来省略这些开销。要了解更多信息,请参阅 此处。
TypeORM 绝对是 node.js 世界中可用的最成熟的对象关系映射器 (ORM)。由于它是用 TypeScript 编写的,因此它与 Nest 框架配合得很好。
入门
要开始使用此库,我们必须安装所有必需的依赖项:
$ npm install --save typeorm mysql2
我们需要做的第一步是使用从 typeorm
包导入的 new DataSource().initialize()
类与我们的数据库建立连接。initialize()
函数返回一个 Promise
,因此我们必须创建一个 异步提供程序。
import { DataSource } from 'typeorm'
export const databaseProviders = [
{
provide: 'DATA_SOURCE',
useFactory: async () => {
const dataSource = new DataSource({
type: 'mysql',
host: 'localhost',
port: 3306,
username: 'root',
password: 'root',
database: 'test',
entities: [
`${__dirname}/../**/*.entity{.ts,.js}`,
],
synchronize: true,
})
return dataSource.initialize()
},
},
]
在生产中不应使用设置 synchronize: true
- 否则您可能会丢失生产数据。
按照最佳实践,我们在带有 *.providers.ts
后缀的分离文件中声明了自定义提供程序。
然后,我们需要导出这些提供程序,使它们可供应用程序的其余部分访问。
import { Module } from '@nestjs/common'
import { databaseProviders } from './database.providers'
@Module({
providers: [...databaseProviders],
exports: [...databaseProviders],
})
export class DatabaseModule {}
现在我们可以使用 @Inject()
装饰器注入 DATA_SOURCE
对象。每个依赖于 DATA_SOURCE
异步提供程序的类都将等待,直到 Promise
被解析。
存储库模式
TypeORM 支持存储库设计模式,因此每个实体都有自己的存储库。这些存储库可以从数据库连接中获取。
但首先,我们至少需要一个实体。我们将重用官方文档中的 Photo
实体。
import { Column, Entity, PrimaryGeneratedColumn } from 'typeorm'
@Entity()
export class Photo {
@PrimaryGeneratedColumn()
id: number
@Column({ length: 500 })
name: string
@Column('text')
description: string
@Column()
filename: string
@Column('int')
views: number
@Column()
isPublished: boolean
}
Photo
实体属于 photo
目录。此目录代表 PhotoModule
。现在,让我们创建一个 Repository 提供程序:
import { DataSource } from 'typeorm'
import { Photo } from './photo.entity'
export const photoProviders = [
{
provide: 'PHOTO_REPOSITORY',
useFactory: (dataSource: DataSource) => dataSource.getRepository(Photo),
inject: ['DATA_SOURCE'],
},
]
在实际应用中,您应该避免使用魔法字符串。PHOTO_REPOSITORY
和 DATA_SOURCE
都应保存在单独的 constants.ts
文件中。
现在我们可以使用 @Inject()
装饰器将 Repository<Photo>
注入到 PhotoService
:
import { Inject, Injectable } from '@nestjs/common'
import { Repository } from 'typeorm'
import { Photo } from './photo.entity'
@Injectable()
export class PhotoService {
constructor(
@Inject('PHOTO_REPOSITORY')
private photoRepository: Repository<Photo>,
) {}
async findAll(): Promise<Photo[]> {
return this.photoRepository.find()
}
}
数据库连接是异步的,但 Nest 使这个过程对最终用户完全不可见。PhotoRepository
正在等待数据库连接,而 PhotoService
则被延迟,直到存储库准备好使用。当每个类被实例化时,整个应用程序就可以启动。
这是最终的 PhotoModule
:
import { Module } from '@nestjs/common'
import { DatabaseModule } from '../database/database.module'
import { photoProviders } from './photo.providers'
import { PhotoService } from './photo.service'
@Module({
imports: [DatabaseModule],
providers: [
...photoProviders,
PhotoService,
],
})
export class PhotoModule {}
不要忘记将 PhotoModule
导入到根 AppModule
。