NestJs學習之路(1)- Typeorm的使用

背景

最近在學習NestJs,可是不從實際需求出發,沒有項目的依託,感受老是個入門而已,只有在解決一個個項目上的問題才能進一步加深和鞏固所學知識,故想將搭建一個博客後臺系統的需求爲出發點,鞏固所學知識,同時也做爲學習新知識、難題解決及注意事項的記錄。mysql

1、安裝依賴

yarn add @nestjs/typeorm typeorm mysql

2、鏈接數據庫(MySQL)

在app.modules中用TypeOrmModule實現數據庫鏈接
// src/app.module.ts

import { Module } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { TypeOrmModule } from '@nestjs/typeorm';

@Module({
  imports: [
    TypeOrmModule.forRootAsync({
      useFactory: () => ({
        type: 'mysql',
        host: 'localhost',
        port: 3306,
        username: 'root',
        password: '',
        database: 'blogs',
        timezone: 'UTC',
        charset: 'utf8mb4',
        entities: ['./**/*.entity.js'],
        synchronize: true,
        logging: true,
    })}),
  ],
  controllers: [AppController],
  providers: [AppService],
})
export class AppModule {}

3、建立entity

entity(實體對象)映射數據庫中的表,entity中的Column與表中的字段相對應
// src/entities/article.entity.ts

import { Entity, Column, PrimaryGeneratedColumn, CreateDateColumn, UpdateDateColumn, DeleteDateColumn } from 'typeorm';

@Entity('article')
export class ArticleEntity {
  @PrimaryGeneratedColumn({
    type: 'int',
    comment: '主鍵id',
  })
  id: number;

  @Column('varchar', {
    nullable: false,
    comment: '文章標題',
  })
  title: string;

  @Column('varchar', {
    nullable: false,
    comment: '文章內容',
  })
  content: string;

  @Column({
    nullable: false,
    name: 'category_id',
    comment: '文章類別',
  })
  categoryID: string;

  @Column('varchar', {
    nullable: true,
    comment: '文章簡介',
  })
  intro: string;

  @Column('varchar', {
    nullable: true,
    comment: '文章封面',
  })
  cover: string;

  @Column('varchar', {
    nullable: true,
    comment: '文章標籤',
  })
  tags: string;

  @Column('enum', {
    nullable: false,
    default: 0,
    enum: [0, 1, 2],
    comment: '文章狀態,0爲編輯中,1爲已發佈,2爲不可用',
  })
  status: number;

  @CreateDateColumn({
    type: 'timestamp',
    name: 'created_at',
    comment: '建立時間',
  })
  createdAt: Date;

  @UpdateDateColumn({
    type: 'timestamp',
    name: 'updated_at',
    comment: '最後更新時間',
  })
  updatedAt: Date;

  @DeleteDateColumn({
    type: 'timestamp',
    name: 'delete_at',
    comment: '刪除',
  })
  deleteAt: Date;
}
// src/entities/article-category.entity.ts
import { Entity, Column, PrimaryGeneratedColumn, CreateDateColumn, UpdateDateColumn, DeleteDateColumn } from 'typeorm';

@Entity('article_category')
export class ArticleCategoryEntity {
  @PrimaryGeneratedColumn({
    type: 'int',
    comment: '主鍵id',
  })
  id: number;

  @Column('varchar', {
    nullable: false,
    unique: true,
    name: 'category_name',
    comment: '文章類別名稱',
  })
  categoryName: string;

  @CreateDateColumn({
    type: 'timestamp',
    name: 'created_at',
    comment: '建立時間',
  })
  createdAt: Date;

  @UpdateDateColumn({
    type: 'timestamp',
    name: 'updated_at',
    comment: '最後更新時間',
  })
  updatedAt: Date;

  @DeleteDateColumn({
    type: 'timestamp',
    name: 'delete_at',
    comment: '刪除',
  })
  deleteAt: Date;
}

Tips:entity要放在/src/entities目錄下,才能在dist目錄下生成.entity.js格式的文件,直接加載.entity.ts文件則會報語法錯誤,以前試過新建libs,而後將數據庫模塊放到libs下,但願將數據庫這部分獨立出來,方便維護;不過發現最後編譯只會在dist生成一個main.js文件,缺乏.entity.js,查看main.js內容發現*.entity.ts編譯的結果也直接放入main.js中。sql

4、數據庫的CURD

EntityManager: 像放一個實體存儲庫的集合的地方,你能夠管理(insert, update, delete, load等)任何實體;能夠經過getManager()或Connection訪問實體管理器。

Repository: 像EntityManager同樣,但其操做僅限於具體實體;能夠經過getRepository(Entity),Connection#getRepository訪問存儲庫。數據庫

下面經過Repository提供的API來實現對數據庫的增刪改查,以及左聯查詢api

// src/service/article/article.service.ts
import { Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { ArticleCategoryEntity } from 'src/entities/article-category.entity';
import { ArticleEntity } from 'src/entities/article.entity';
import { Repository, createQueryBuilder, getConnection, getRepository } from 'typeorm';

@Injectable()
export class ArticleService {
    constructor(
        @InjectRepository(ArticleCategoryEntity)
        private readonly articleCategoryRepo: Repository<ArticleCategoryEntity>,
        @InjectRepository(ArticleEntity)
        private readonly articleRepo: Repository<ArticleEntity>,
    ) {

    }

    /**
     * 獲取文章分類
     */
    getArticleCate() {
        return this.articleCategoryRepo.find();
    }

    /**
     * 建立文章分類
     * @param body
     */
    createArticleCate(body): Promise<any> {
        const userEntity = this.articleCategoryRepo.create(body);
        return this.articleCategoryRepo.save(userEntity);
    }

    /**
     * 刪除文章分類
     * @param id 文章分類ID
     */
    delArticleCate(id): Promise<any> {
        return this.articleCategoryRepo.delete(id);
    }

    /**
     * 獲取文章
     * @param id 文章ID
     */
    getArticle(id) {
        // 利用leftJoinAndMapOne方法進行左聯查詢
        // 兩個未關聯的實體,經過getRawMany獲取原始查詢數據
        if (id) {
            return createQueryBuilder(ArticleEntity, 'article')
                .leftJoinAndMapOne('article.cate_name', ArticleCategoryEntity, 'cate', 'cate.id = article.category_id')
                .where('article.id = :id', { id })
                .select(['article.*', 'cate.category_name'])
                .getRawMany(); // 得到原始結果
        } else {
            return createQueryBuilder(ArticleEntity, 'article')
                .leftJoinAndMapOne('article.cate_name', ArticleCategoryEntity, 'cate', 'cate.id = article.category_id')
                .getRawMany(); // 得到原始結果
        }
    }

    /**
     * 建立文章
     * @param body
     */
    createArticle(body) {
        const articleEntity = this.articleRepo.create(body);
        return this.articleRepo.save(articleEntity);
    }

    /**
     * 更新文章
     * @param id
     * @param body
     */
    updateArticle(id, body) {
        return this.articleRepo.update(id, body);
    }

    /**
     * 刪除文章
     * @param id 文章ID
     */
    delArticle(id) {
        return this.articleRepo.delete(id);
    }
}
相關文章
相關標籤/搜索