Nestjs🐺⚡ | Nodejs 框架(第三部分)| 数据库集成,TypeORM

2025-06-09

Nestjs🐺⚡ | Nodejs 框架(第三部分)| 数据库集成,TypeORM

如果你还没有读过第一部分第二部分,请先阅读它们,否则你会觉得这篇文章脱离了背景

在这一部分,我将讨论

  • Nestjs 数据库集成
  • 基本 Typeorm

数据库集成

后端服务/API 的主要部分是其数据库管理系统

重要提示:本文是关于 Nestjs 的,而不是关于数据库(SQL/NoSQL),所以我假设阅读本文的人对 DBMS 有基本的了解

由于 Nestjs 只是对典型 Nodejs 服务器 API/包的抽象,因此它支持各种流行的数据库及其大多数 ORM。它支持以下数据库驱动程序和 ORM:

  • Typeorm(SQL/NoSQL)
  • MikroORM(SQL/NoSQL)
  • 克内克斯
  • 棱镜
  • 猫鼬(NoSQL)

我在这里使用 TypeORM,因为在我看来,它与 Nestjs 的 API 方案最为匹配,因为它采用了装饰器模式。此外,我还使用 PostgreSQL 作为数据库。你也可以根据需要使用其他数据库和 ORM。它们的配置模式基本相同。此外,总有官方/第三方软件包和文档供你选择。谷歌一下就行了。

首先安装:

# for npm users*
$ npm i @nestjs/typeorm typeorm psql
# for yarn user
$ yarn add @nestjs/typeorm typeorm psql
Enter fullscreen mode Exit fullscreen mode

注意!:请先在操作系统中安装 PostgreSQL 驱动程序或您选择的数据库驱动程序。PostgreSQL 的安装说明可在此处找到。

现在在项目根目录中创建以下文件:

  • .env(用于存储数据库凭证和机密)
  • config.ts(用于导入环境变量)
  • ormconfig.ts(数据库连接配置)
#### .env #####
POSTGRES_PASSWORD=simplepassword
POSTGRES_DB=hello
NODE_ENV=development
DATABASE_USERNAME=postgres # you can put your username of your OS
DATABASE_HOST=localhost # use `postgres` if using PostgreSQL Docker Container
DATABASE_PORT=5432
PORT=4000
Enter fullscreen mode Exit fullscreen mode

现在导入此环境变量并重新导出项目

///// config.ts //////
export const NODE_ENV = process.env.NODE_ENV;
// all the env vars
export const DATABASE_HOST = process.env.DATABASE_HOST;
export const DATABASE_PORT = process.env.DATABASE_PORT
    ? parseInt(process.env.DATABASE_PORT)
    : undefined;
export const DATABASE_NAME = process.env.POSTGRES_DB;
export const DATABASE_PASSWORD = process.env.POSTGRES_PASSWORD;
export const DATABASE_USERNAME = process.env.DATABASE_USERNAME;
export const PORT = process.env.PORT ?? 4000;
Enter fullscreen mode Exit fullscreen mode

创建数据库连接:

///// ormconfig.ts /////
import {
    DATABASE_HOST,
    DATABASE_NAME,
    DATABASE_PASSWORD,
    DATABASE_PORT,
    DATABASE_USERNAME,
    NODE_ENV,
} from "./config";
import { PostgresConnectionOptions } from "typeorm/driver/postgres/PostgresConnectionOptions";

// db configuration for the orm
const ormconfig: PostgresConnectionOptions = {
    type: "postgres", // name of db you'll be using
    username: DATABASE_USERNAME,
    database: DATABASE_NAME,
    host: DATABASE_HOST,
    port: DATABASE_PORT,
    password: DATABASE_PASSWORD,
    uuidExtension: "uuid-ossp", // for using `uuid` as the type for Primary-Column `id` column
    synchronize: NODE_ENV !== "production",
};

export = ormconfig;
Enter fullscreen mode Exit fullscreen mode

现在生成一个名为的模块database,用于保存所有与数据库相关的配置/文件。以下命令将生成它:

$ npx nest g module database
Enter fullscreen mode Exit fullscreen mode

database.module.ts在配置里面使用 TypeORM 注册数据库连接:

///// database.module.ts //////

import { Module } from '@nestjs/common';
import ormconfig from "../../ormconfig";
import { TypeOrmModule } from "@nestjs/typeorm";

@Module({
  imports: [
       // registers Database config
        TypeOrmModule.forRoot({
            ...ormconfig, //db config
            entities: [], // put the constructor of all classes that are an Entity
        }),
    ],
})
export class DatabaseModule {}
Enter fullscreen mode Exit fullscreen mode

希望在重新启动应用程序后,您的 API/服务将与数据库连接

提示!:你可以在函数中传递一个 ORM 配置数组,TypeOrmModule.forRoot()用于多个数据库连接。这样可以同时使用任何类型的数据库。

类型ORM

本教程并非关于 TypeORM 的,但我会对其进行一些解释,以便入门。更多信息请参阅他们的文档。

TypeORM 的 SQL/NoSQL API 各有不同。这里我仅展示 SQL 部分。如果您使用的是 NoSQL 数据库(例如 MongoDB),并且使用了 TypeORM,那么您可以点击此处进行学习。

如果你读过第二部分,你可能知道,我之前用类属性作为内存临时数据库。现在我们将通过反射器实现这一部分,以便通过 TypeOrm 使用新的 PostgreSQL 数据库。

首先,创建src/database/entities/hello-record.entity.ts,然后创建 TypeORM 模式:

///// hello-record.entity.ts /////

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

@Entity('hello-record')
export class HelloRecord {
  @PrimaryGeneratedColumn('uuid')
  id!: string;

  @Column('varchar', { length: 16 })
  from!: string;

  @Column('text')
  msg!: string;
}
Enter fullscreen mode Exit fullscreen mode

你可以使用装饰器将一个类声明为 TypeORM 实体@Entity()。你可以为该实体指定一个名称(你应该始终这样做),或者让 TypeORM 根据该类的显示名称创建一个名称。

要创建主列,@PrimaryGeneratedColumn请使用 。您可以使用rowIdincrementeduuid作为主列类型。请记住启用 PostgreSQL 数据库或任何 SQL 数据库的 UUID 扩展,以便使用 uuid

要创建列,@Column需要使用装饰器。您可以指定列的类型或该列的任何内容。我varchar为列“ from”使用了 16 个字符的长度,因为它将用于存储发布问候消息的用户的 IP 地址text此外,我为“ ”列使用了类型,msg因为我们不想像某些社交媒体那样将每个人的长度限制为 240 个字符。这太不人道了🤐

现在,为了让 TypeORM 知道HelloRecord它的存在,我们必须将它放入函数entities数组Typeorm.forRoot()database.module.ts。你必须将应用程序中使用的所有实体都放入该数组中。顺便说一句,如果你使用多个数据库连接,请将为特定数据库专门创建的实体放入特定数据库的配置对象entities数组中。同一个实体不能用于多个数据库。

///// database.module.ts //////

// .... (other imported stuffs)
import { HelloRecord } from './entities/hello-record.entity';

@Module({
  imports: [
    TypeOrmModule.forRoot({
      ...ormconfig,
      // put all the entities related to the database in here
      entities: [
        HelloRecord,
      ],
    }),
  ],
})
export class DatabaseModule {}
Enter fullscreen mode Exit fullscreen mode

重要提示!:切勿在实体/模式声明中使用继承。如果某些实体共享相同类型的属性/列,请勿为它们创建一个通用类,然后从中继承。这可能会导致模式同步问题,因为 TypeORM 无法获知该父类属性的类型。模式继承并非 DRY 原则,而是对 DRY(不要重复自己)的过度使用。所以永远不要这样做。

现在我们已经创建了实体,让我们在我们的中使用它HelloService。但我们必须将其导入,HelloModule以便让 Nest 知道它属于HelloModule

////// hello.module.ts //////

// .... (other imported stuff)
import { TypeOrmModule } from '@nestjs/typeorm';

@Module({
  imports: [
    forwardRef(() => HiModule),
    // labelling the entity as `HelloModule`'s Repository
    TypeOrmModule.forFeature([HelloRecord]),
  ],
  providers: [HelloService, ByeService],
  controllers: [HelloController],
  exports: [HelloService],
})
export class HelloModule {}
Enter fullscreen mode Exit fullscreen mode

TypeOrmModule.forFeature将允许访问 的HelloRecord所有提供程序/控制器中的实体HelloModule。顺便说一句,您不能在不同模块中多次标记同一个实体。如果您想在其他模块中访问该实体,只需导入使用该实体的提供程序即可。

现在让我们重构HelloService以使用新的实体来保存、修改和读取hello 消息:

////// hello.service.ts ///////

import { forwardRef, Inject, Injectable } from '@nestjs/common';
import { HiService } from 'src/hi/hi.service';
import { ByeService } from './bye.service';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { HelloRecord } from '../database/entities/hello-record.entity';

@Injectable()
export class HelloService {
  constructor(
    @Inject(forwardRef(() => HiService))
    private hiService: HiService,
    @Inject(forwardRef(() => ByeService))
    private byeService: ByeService,
    @InjectRepository(HelloRecord)
    private helloRecordRepo: Repository<HelloRecord>,
  ) {}

    async findById(id: string) {
    return await this.helloRecordRepo.findOneOrFail({ id });
  }

  async create(msg: string, ip: string) {
    const newMsg = this.helloRecordRepo.create({ msg, from: ip });
    return await newMsg.save();
  }

  async deleteById(id: string) {
    return await this.helloRecordRepo.delete({ id });
  }

  getHello(arg: string) {
    return `hello for ${arg}`;
  }

  // a method that uses `hiService`
  hiServiceUsingMethod() {
    return this.hiService.getHi('hello');
  }

  byeServiceUsingMethod() {
    return this.byeService.getBye('hello');
  }

Enter fullscreen mode Exit fullscreen mode

TypeORM 提供了创建、删除和修改数据所需的所有方法。以下是一些最常用的方法:

  • EntityName.findOne(按条件查找并返回第一个匹配的记录作为承诺)
  • EntityName.findOneOrFail(就像findOne但如果没有找到记录则会抛出错误。总是尝试使用它而不是findOne因为它支持错误处理)
  • EntityName.find(查找所有符合条件的记录并以承诺形式返回)
  • EntityName.save(保存传递给它的任何与该实体的模式匹配的对象。也可用于修改/更新记录)
  • EntityName.create(创建一个新的软记录,并将其作为参数传递给EntityName.save
  • EntityName.delete(删除所有符合传递条件的记录)
  • EntityName.createQueryBuilder(替代查询 API,使用字符串来操作 SQL 事务,而不是使用面向对象的方法。它更像是一种函数式方法。它遵循流行的构建器模式并支持方法链。它更接近原生 SQL)

最终工作应用程序:


到这里,我结束Nestjs🐺⚡ | Nodejs 的框架系列

Nestjs 是一个非常棒的后端框架,提供了开发企业级、可靠的服务器应用程序/API 所需的所有必要工具。本系列文章只是对 Nestjs 的更高层次的概述,只涉及了很少的概念和功能。Nestjs 提供的远不止这些。Nest 的官方文档提供了关于 Nestjs 更深入、更清晰的概述和教程。他们还提供企业支持。

Nestjs 不仅仅是一个工具/框架/库,它也是你的指南

鏂囩珷鏉ユ簮锛�https://dev.to/krtirtho/nestjs-the-framework-of-nodejs-part-3-database-integration-typeorm-4gab
PREV
你需要的 VSCode 扩展 [Webdevs]🚀🔧
NEXT
如何成为高级开发人员