nestjs搭建通用业务框架(7):TypeORM进阶CURD操作

这是《nestjs搭建通用业务框架》系列的第7篇,主要介绍了nestjs中的TypeORM的具体使用方案。两种情况:1. 有数据库设计的情况,使用typeorm-model-generator产生实体类;2. 无数据库的情况,可以手动创建实体类后,使用typeorm的synchronize属性,来同步创建表格;

TypeORM上手

在前置的篇章中《nestjs搭建通用业务框架(5):数据库+配置》,我们有介绍如何集成TypeORM到我们的nest项目中。平时的使用,无非两种情况:

  1. 我们清楚的知道数据库及表格设计,我们不想去建TypeORM的实体ts文件;
  2. 我们清楚的知道实体类的字段类型,我们不想去建数据库,全交给ORM;

我们先来看第一种情况:

如何产生typeORM的实体类

typeorm-model-generator

  • 针对 mysql

    1
    npx typeorm-model-generator -h localhost -d your-mysql-db -u root -x your-mysql-password -e mssql -o .
  • 针对progres:

    1
    npx typeorm-model-generator -h localhost -d postgres -u postgres -x !Passw0rd -e postgres -o .

参数说明:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
Usage: typeorm-model-generator -h <host> -d <database> -p [port] -u <user> -x
[password] -e [engine]

Options:
--help Show help [boolean]
--version Show version number [boolean]
-h, --host IP address/Hostname for database server
[default: "127.0.0.1"]
-d, --database Database name(or path for sqlite) [required]
-u, --user Username for database server
-x, --pass Password for database server [default: ""]
-p, --port Port number for database server
-e, --engine Database engine
[choices: "mssql", "postgres", "mysql", "mariadb", "oracle", "sqlite"]
[default: "mssql"]
-o, --output Where to place generated models
[default: "./output"]
-s, --schema Schema name to create model from. Only for mssql
and postgres. You can pass multiple values
separated by comma eg. -s scheme1,scheme2,scheme3
--ssl [boolean] [default: false]
  • -e 对应的数据库的类型
  • -p数据库服务器的端口
  • -d数据库的名称
  • -u数据库的用户名
  • -smssqlpostgres设计的一个参数,可以设置schema的名称

比如,我们的项目中是这样用的:

由于事先已经建好了users这个表格,里面就只有id, usernamepassword三个字段。

1
npx typeorm-model-generator -h localhost -d nest-common -u root -x 123456 -e mysql -o .

产生三个文件:

1
2
3
4
5
.
├── entities
│ └── Users.ts
├── ormconfig.json
└── tsconfig.json

这里只需要这个文件Users.ts,然后大家可以把这个文件放置到src/entities或者其他的src的目录中,重启项目。

Users.ts文件的内容:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
import { Column, Entity, Index, PrimaryGeneratedColumn } from 'typeorm';

@Index('username_Idx', ['username'], { unique: true })
@Entity('users', { schema: 'nest-common' })
export class Users {
@PrimaryGeneratedColumn({ type: 'int', name: 'id' })
id: number;

@Column('varchar', { name: 'username', unique: true, length: 32 })
username: string;

@Column('varchar', { name: 'password', length: 255 })
password: string;
}

后续,我们建议使用nest g res [Module-Name]的方式来进行创建基础的CURD + 文件结构。

下面再来看第二种情况:

关于配置entities路径

推荐配置src/config/devlopment.ts

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
import * as path from 'path';

export const resolve = (dir) =>
path.join(path.resolve(__dirname, '../../'), dir);
// 这里大家可以打印一下路径
// __dirname: /Users/macos/Projects/nestjs/nestjs-common-template/dist/config
// 惊讶的发现,目录是dist目录中的config路径

export const config = {
db: {
// https://typeorm.io/#/connection-options/common-connection-options
synchronize: true,
logging: true,
host: process.env.DB_HOST || '127.0.0.1',
port: process.env.DB_PORT || 3306,
username: process.env.DB_USER || 'root',
password: process.env.DB_PASSWORD || '123456',
database: process.env.DB_NAME || 'nest-common',
// 这里对应的路径是 /Users/macos/Projects/nestjs/nestjs-common-template/dist/**/*.entity{.ts,.js}
// 即 dist 目录中,所有以 .entity.ts 或者 .entity.js 结尾的文件
entities: [resolve('dist') + '/**/*.entity{.ts,.js}'],
extra: {
connectionLimit: 30,
},
},
};

这里几个有意思的属性:

  • synchronizetrue代表会从entities属性产生SQL,并创建表格;

    如果,你的数据库中没有,那么则会创建表的SQL,并自动创建

    测试:

    1. 删除users表格
    2. 重启npm调试进程
    3. 刷新数据库,users表又回来了
  • loggingtrue代表执行SQL会打印在控制台中

  • entities:TypeORM读取的实体类的文件夹,及文件名。

快速创建CURD服务

官方nest g方案

使用命令nest g res users,默认回车:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
nest g res users
? What transport layer do you use? (Use arrow keys)
❯ REST API
GraphQL (code first)
GraphQL (schema first)
Microservice (non-HTTP)
WebSockets
? Would you like to generate CRUD entry points? (Y/n)
CREATE src/users/users.controller.spec.ts (566 bytes)
CREATE src/users/users.controller.ts (894 bytes)
CREATE src/users/users.module.ts (247 bytes)
CREATE src/users/users.service.spec.ts (453 bytes)
CREATE src/users/users.service.ts (609 bytes)
CREATE src/users/dto/create-user.dto.ts (30 bytes)
CREATE src/users/dto/update-user.dto.ts (169 bytes)
CREATE src/users/entities/user.entity.ts (21 bytes)
UPDATE src/app.module.ts (1150 bytes)

是不是很方便。

使用ORM步骤:

  1. 打开users/entities/user.entity.ts,把之前生成的实体类加入进来,或者自己进行编辑。

  2. 修改users/users.module.ts,导入ORM:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    import { Module } from '@nestjs/common';
    import { UsersService } from './users.service';
    import { UsersController } from './users.controller';
    import { Users } from './entities/user.entity';
    // 这里导入
    import { TypeOrmModule } from '@nestjs/typeorm';

    @Module({
    // 这里导入
    imports: [TypeOrmModule.forFeature([Users])],
    controllers: [UsersController],
    providers: [UsersService],
    })
    export class UsersModule {}
  3. 修改users/users.service.ts文件,添加get请求,并通过ORM操作数据库:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    // ...
    import { InjectRepository } from '@nestjs/typeorm';


    @Injectable()
    export class UsersService {
    constructor(
    // 这里添加了Repository
    @InjectRepository(Users)
    private readonly usersRepository: Repository<Users>,
    ) {}

    // ...

    async findAll() {
    // 返回usres表中的所有数据
    return await this.usersRepository.find(),
    }

    // ...
    }
  4. 添加users一条信息,并测试:localhost:3000/users GET请求

    1
    2
    3
    4
    5
    6
    7
    [
    {
    "id": 1,
    "username": "123",
    "password": "123"
    }
    ]

    直接返回一个json数组。

nestjsx方案

  1. 什么是nestjsx

    一个致力于开发nestjs的扩展的github组织。

  2. 为什么要用nestjsx?

    官方:NestJS可能是几年前Node.js社区发生的最好的事情之一,为广泛的后端开发方面提供了一个真正重要的架构解决方案。但是,尽管它允许有效地创建RESTful应用程序,但缺少了一个重要的CRUD脚手架功能,而这个功能在许多其他HTTP框架中是存在的。这就是Nestjsx/crud问世的原因。

  3. nestjsx的各个包的作用是什么

    @nestjsx/crud - 核心包,它提供了@Crud()装饰器,用于端点生成、全局配置、验证、辅助装饰器(文档)。
    @nestjsx/crud-typeorm - TypeORM包,它为关系型数据库提供了带有CRUD数据库操作方法的基础TypeOrmCrudService
    @nestjsx/crud-request - 请求生成器/解析器包,它提供了用于前端的RequestQueryBuilder类和用于内部处理和验证后端查询/路径参数的RequestQueryParser

上手使用:

1
2
3
4
5
# 安装
npm i @nestjsx/crud class-transformer class-validator

# 使用 TypeORM
npm i @nestjsx/crud-typeorm @nestjs/typeorm typeorm @nestjs/swagger

修改users.service.ts

1
2
3
4
5
6
7
8
9
10
11
import { Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { TypeOrmCrudService } from '@nestjsx/crud-typeorm';
import { Users } from './entities/user.entity';

@Injectable()
export class UsersService extends TypeOrmCrudService<Users> {
constructor(@InjectRepository(Users) repo) {
super(repo);
}
}

修改users.controller.ts

1
2
3
4
5
6
7
8
9
10
11
12
13
14
import { Controller } from '@nestjs/common';
import { UsersService } from './users.service';
import { Users } from './entities/user.entity';
import { Crud, CrudController } from '@nestjsx/crud';

@Crud({
model: {
type: Users,
},
})
@Controller('users')
export class UsersController implements CrudController<Users> {
constructor(public service: UsersService) {}
}

再次请求localhost:3000/users,结果与之前的相同。