乐闻世界logo
搜索文章和话题
基于 NestJS 操作 TypeORM 中的多对多 ManyToMany

基于 NestJS 操作 TypeORM 中的多对多 ManyToMany

乐闻的头像
乐闻

2024年01月01日 10:59· 阅读 2620

前言

TypeORM 是一个在 TypeScript 和 JavaScript (ES7, ES6, ES5) 中提供了许多开箱即用特性的 ORM,它能够改善我们处理数据库操作的效率与可维护性。在复杂的应用开发过程中,数据间的关系处理显得尤其重要。今天我们将在 NestJS 中探索 TypeORM 的 ManyToMany(多对多)关系,这是一种常见且强大的数据模型关系。在建立应用程序时,我们通常需要处理大量的增删查改(CRUD)操作,而 ManyToMany 关系的有效应用能够让这些操作变得更为简洁、优雅。

使用步骤

一、安装依赖

首先需要在我们的 NestJS 应用中安装并设置 TypeORM。在你的项目根目录下执行以下命令:

text
npm install --save @nestjs/typeorm typeorm

二、模块初始化

在项目的 app.module.ts 文件中进行 TypeORM 的设置。

typescript
import { Module } from '@nestjs/common'; import { TypeOrmModule } from '@nestjs/typeorm'; import { AppController } from './app.controller'; import { AppService } from './app.service'; import { Author } from './author.entity'; import { Book } from './book.entity'; @Module({ imports: [ TypeOrmModule.forRoot({ type: 'postgres', host: 'localhost', port: 5432, username: 'test', password: 'test', database: 'test', entities: [Author, Book], synchronize: true, }), ], controllers: [AppController], providers: [AppService], }) export class AppModule {}

三、建立多对多的实体关系

我们创建 作者 书籍这两个实体。作者可以写多本书,一本书也可以有多个作者。

Author

typescript
import {Entity, Column, ManyToMany, PrimaryGeneratedColumn, JoinTable} from 'typeorm'; import { Book } from './book.entity'; @Entity() export class Author { @PrimaryGeneratedColumn() id: number; @Column() name: string; @ManyToMany(type => Book, book => book.authors) @JoinTable() books: Book[]; }

Book

typescript
import {Entity, Column, ManyToMany, PrimaryGeneratedColumn} from 'typeorm'; import { Author } from './author.entity'; @Entity() export class Book { @PrimaryGeneratedColumn() id: number; @Column() title: string; @ManyToMany(type => Author, author => author.books) authors: Author[]; }

四、实现对应的服务层

为了创建作者和他们的书籍,我们需要创建一个服务。服务通过依赖注入来定义在各个模块之间的关系,你需要记住的一点是:在 NestJS 中,你需要使用 Repository 来操作数据库。

Author Service

typescript
import { Injectable } from '@nestjs/common'; import { InjectRepository } from '@nestjs/typeorm'; import { Repository } from 'typeorm'; import { Author } from './author.entity'; import { Book } from './book.entity'; @Injectable() export class AuthorService { constructor( @InjectRepository(Author) private authorRepository: Repository<Author>, @InjectRepository(Book) private bookRepository: Repository<Book>, ) {} async createAuthorWithBooks() { const author = this.authorRepository.create({ name: 'John Doe' }); const book1 = this.bookRepository.create({ title: 'Book #1', }); const book2 = this.bookRepository.create({ title: 'Book #2', }); author.books = [book1, book2]; await this.authorRepository.save(author); // ... } }

五、多对多的增删改查操作

  • 新增 Create

    在 AuthorService 中,我们已经创建了 createAuthorWithBooks 方法,可以同时创建作者和对应的书籍:

    typescript
    async createAuthorWithBooks() { const author = this.authorRepository.create({ name: 'John Doe' }); const book1 = this.bookRepository.create({ title: 'Book #1', }); const book2 = this.bookRepository.create({ title: 'Book #2', }); author.books = [book1, book2]; await this.authorRepository.save(author); }
  • 删除 Remove

    删除某一本书,可以通过 remove 方法来达成:

    typescript
    async deleteBook(bookId: number) { let toDelete = await this.bookRepository.findOne(bookId); let deleted = false; if (toDelete) { await this.bookRepository.remove(toDelete); deleted = true; } return { deleted }; }
  • 修改 Update

    假设我们要更新某一本书的信息,可以通过 update 方法来操作:

    typescript
    async updateBook(bookId: number, updatedTitle: string) { let toUpdate = await this.bookRepository.findOne(bookId); let updated = false; if (toUpdate) { toUpdate.title = updatedTitle; await this.bookRepository.save(toUpdate); updated = true } return { updated }; }
  • 查询 Search

    例如我们想要查找一个作者所有的书,可以创建如下方法:

    typescript
    async findBooksByAuthor(authorId: number) { return this.bookRepository.createQueryBuilder("book") .innerJoinAndSelect("book.authors", "author") .where("author.id = :authorId", { authorId }) .getMany(); }
  • 列表查询

    假设我们想要查询所有的作者列表,可以通过 find 方法实现:

    typescript
    async findAllAuthors() { return await this.authorRepository.find(); }

进阶操作

一、分页查询

当你的数据太多,你可能需要进行分页查询。我们可以使用 take 和 skip 方法进行分页查询。

下面这个方法展示了如何获取第二页的作者,每页有5个作者:

typescript
async findAuthorsPagination(page: number) { return await this.authorRepository.find({ take: 5, skip: 5 * (page - 1), }); }

在这个方法中, take 表示要获取的条数,skip 表示要跳过的条数。

二、关联查询

假设我们需要获取包含了一个作者的所有书的信息,我们就需要做一个关联查询:

typescript
async findAuthorAndBooks(authorId: number) { return this.authorRepository.findOne(authorId, { relations: ["books"] }); }

这个 findOne 方法会返回一个 Author 对象,该对象包含一个 Book 对象的数组,表示该作者写的所有书。

总结

在使用 NestJS 和 TypeORM 进行开发时,我们已经掌握了 ManyToMany(多对多)关系的设定、如何进行基础的 CRUD(增删查改)操作,还了解了列表查询、分页查询及关联查询的实现方式。最后,不要忘记,TypeORM 的 ManyToMany 关系默认情况下是懒加载的,使得我们在需要时才去加载关联数据,提升了程序的运行效率。借助 NestJS 和 TypeORM,我们能够轻松处理复杂的数据关联关系,提升开发效率。

标签: