ThinkChat2.0新版上线,更智能更精彩,支持会话、画图、阅读、搜索等,送10W Token,即刻开启你的AI之旅 广告
## TypeORM **本章仅适用于TypeScript** > 在本文中,您将学习如何使用自定义提供者机制从零开始创建基于 **TypeORM** 包的 `DatabaseModule` 。由于该解决方案包含许多开销,因此您可以使用开箱即用的 `@nestjs/typeorm` 软件包。要了解更多信息,请参阅 [此处](https://docs.nestjs.com/techniques/sql)。 [TypeORM](https://github.com/typeorm/typeorm) 无疑是 `node.js` 世界中最成熟的对象关系映射器(`ORM` )。由于它是用 `TypeScript` 编写的,所以它在 `Nest` 框架下运行得非常好。 ### 入门 在开始使用这个库前,我们必须安装所有必需的依赖关系 ```bash $ npm install --save typeorm mysql2 ``` 我们需要做的第一步是使用从 `typeorm` 包导入的 `createConnection()` 函数建立与数据库的连接。`createConnection()` 函数返回一个 `Promise`,因此我们必须创建一个[异步提供者](/8/fundamentals.md?id=异步提供者 ( `Asynchronous providers` ))。 > database.providers.ts ```typescript import { createConnection } from 'typeorm'; export const databaseProviders = [ { provide: 'DATABASE_CONNECTION', useFactory: async () => await createConnection({ type: 'mysql', host: 'localhost', port: 3306, username: 'root', password: 'root', database: 'test', entities: [ __dirname + '/../**/*.entity{.ts,.js}', ], synchronize: true, }), }, ]; ``` >不应在生产中使用设置 synchronize: true - 否则您可能会丢失生产数据。 > 按照最佳实践,我们在分离的文件中声明了自定义提供者,该文件带有 `*.providers.ts` 后缀。 然后,我们需要导出这些提供者,以便应用程序的其余部分可以 **访问** 它们。 > database.module.ts ```typescript import { Module } from '@nestjs/common'; import { databaseProviders } from './database.providers'; @Module({ providers: [...databaseProviders], exports: [...databaseProviders], }) export class DatabaseModule {} ``` 现在我们可以使用 `@Inject()` 装饰器注入 `Connection` 对象。依赖于 `Connection` 异步提供者的每个类都将等待 `Promise` 被解析。 ### 存储库模式 [TypeORM](https://github.com/typeorm/typeorm) 支持存储库设计模式,因此每个实体都有自己的存储库。这些存储库可以从数据库连接中获取。 但首先,我们至少需要一个实体。我们将重用官方文档中的 `Photo` 实体。 > photo.entity.ts ```typescript import { Entity, Column, 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` 。现在,让我们创建一个 **存储库** 提供者: > photo.providers.ts ```typescript import { Connection, Repository } from 'typeorm'; import { Photo } from './photo.entity'; export const photoProviders = [ { provide: 'PHOTO_REPOSITORY', useFactory: (connection: Connection) => connection.getRepository(Photo), inject: ['DATABASE_CONNECTION'], }, ]; ``` !> 请注意,在实际应用程序中,您应该避免使用魔术字符串。`PhotoRepositoryToken` 和 `DbConnectionToken` 都应保存在分离的 `constants.ts` 文件中。 在实际应用程序中,应该避免使用魔法字符串。`PHOTO_REPOSITORY` 和 `DATABASE_CONNECTION` 应该保持在单独的 `constants.ts` 文件中。 现在我们可以使用 `@Inject()` 装饰器将 `Repository<Photo>` 注入到 `PhotoService` 中: > photo.service.ts ```typescript import { Injectable, Inject } from '@nestjs/common'; import { Repository } from 'typeorm'; import { Photo } from './photo.entity'; @Injectable() export class PhotoService { constructor( @Inject('PHOTO_REPOSITORY') private readonly photoRepository: Repository<Photo>, ) {} async findAll(): Promise<Photo[]> { return this.photoRepository.find(); } } ``` 数据库连接是 **异步的**,但 `Nest` 使最终用户完全看不到这个过程。`PhotoRepository` 正在等待数据库连接时,并且`PhotoService` 会被延迟,直到存储库可以使用。整个应用程序可以在每个类实例化时启动。 这是一个最终的 `PhotoModule` : > photo.module.ts ```typescript 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` 导入到根 `ApplicationModule` 中。