写在前面
在上一篇文章《【前端】嘿,Nest.js实战开发系列 01 ── Nest.js初体验》中介绍了如何上手nest.js,同时详细介绍了如何进行项目创建、路由访问和创建模块,这些都是项目实践的基础。随着项目的推进,我们就要考虑如何实现数据库的连接和使用,这样可以用来实现前后端数据交互的数据存储。
环境准备:
- Mysql 5.7
- TypeORM 0.2.34
TypeORM集成
在Nest.js中可以使用任意数据库,且内部集成提供了TypeORM 和 Sequelize ,开箱即用@nestjs/typeorm和@nestjs/sequelize包。Nest 使用TypeORM,因为它是可用于 TypeScript 的最成熟的对象关系映射器 (ORM)。由于它是用 TypeScript 编写的,因此它可以很好地与 Nest 框架集成。
要开始使用它,我们首先安装所需的依赖项。在命令行中输入:
- $ npm install --save @nestjs/typeorm typeorm mysql2
安装完毕后,可以将TypeOrmModule导入根目录AppModule。
app.module.ts
- import { Module } from '@nestjs/common';
- import { TypeOrmModule } from '@nestjs/typeorm';
- @Module({
- imports: [
- TypeOrmModule.forRoot({
- type: 'mysql',
- host: 'localhost',
- port: 3306,
- username: 'root',
- password: 'root',
- database: 'test',
- entities: [],
- synchronize: true,
- }),
- ],
- })
- export class AppModule {}
切记:synchronize: true不应在生产中使用设置- 否则您可能会丢失生产数据。
该forRoot()方法支持TypeORM包中的createConnection()函数公开的所有配置属性。此外,还有几个额外的配置属性如下所述。
当然,也可以在根目录下创建ormconfig.json文件,在文件中进行数据库信息的设置。
ormconfig.json
- {
- "type": "mysql",
- "host": "localhost",
- "port": 3306,
- "username": "root",
- "password": "root",
- "database": "test",
- "entities": ["dist/**/*.entity{.ts,.js}"],
- "synchronize": true
- }
然后,我们可以在forRoot()没有任何选项的情况下调用:
app.module.ts
- import { Module } from '@nestjs/common';
- import { TypeOrmModule } from '@nestjs/typeorm';
- @Module({
- imports: [TypeOrmModule.forRoot()],
- })
- export class AppModule {}
注意:静态 glob 路径(例如,dist/**/*.entity{ .ts,.js})将无法与webpack正常工作。
其实,ormconfig.json文件是由typeorm库加载的,因此不会应用额外的属性设置。TypeORM 提供了getConnectionOptions从ormconfig文件或环境变量中读取连接选项的函数。
完成以上操作后,TypeORMConnection和EntityManager对象将可用于在整个项目中注入(无需导入任何模块)。
app.module.ts
- import { TypeOrmModule } from '@nestjs/typeorm';
- import { Connection } from "typeorm";
- import { UsersModule } from './users/users.module';
- @Module({
- imports: [
- TypeOrmModule.forRoot(),
- UsersModule
- ],
- controllers: [AppController],
- providers: [AppService],
- })
- export class AppModule {
- constructor(private connection: Connection){}
- }
存储库模式
TypeORM支持存储库设计模式,因此每个实体都有自己的存储库。这些存储库可以从数据库连接中获得。
下面创建一个用户实体,users.entity.ts在users目录下,
users.entity.ts
- import {Entity, PrimaryGeneratedColumn, Column, BeforeInsert, JoinTable, ManyToMany, OneToMany} from 'typeorm';
- import { IsEmail } from 'class-validator';
- import * as argon2 from 'argon2';
- import { ArticleEntity } from '../article/article.entity';
- @Entity('user')
- export class UserEntity {
- @PrimaryGeneratedColumn()
- id: number;
- @Column()
- username: string;
- @Column()
- @IsEmail()
- email: string;
- @Column({default: ''})
- bio: string;
- @Column({default: ''})
- image: string;
- @Column()
- password: string;
- @BeforeInsert()
- async hashPassword() {
- this.password = await argon2.hash(this.password);
- }
- @ManyToMany(type => ArticleEntity)
- @JoinTable()
- favorites: ArticleEntity[];
- @OneToMany(type => ArticleEntity, article => article.author)
- articles: ArticleEntity[];
- }
现在开始使用Users实体,只需要在users.module.ts文件中通过entities模块forFeature()方法选项中的数组来进行导入。
users.module.ts
- import { Module } from '@nestjs/common';
- import { UsersController } from './users.controller';
- import { UsersService } from './users.service';
- import {UsersEntity} from "./users.entity";
- import { TypeOrmModule } from '@nestjs/typeorm';
- @Module({
- imports: [TypeOrmModule.forFeature([UsersEntity])],
- providers: [UsersService],
- controllers: [
- UsersController
- ],
- exports: [UsersService]
- })
- export class UsersModule {}
此模块使用forFeature()来定义在当前范围内注册了那些存储库,此时将可以使用装饰器将UsersRepository注入到`UsersService @InjectRepository().
users.service.ts
- import {Get, Post, Body, Put, Delete, Query, Param, Controller} from '@nestjs/common';
- import { UsersService } from './users.service';
- @Controller('user')
- export class UsersController {
- constructor(private readonly usersService: UsersService){}
- // 查找指定用户
- @Get("find/:id")
- async findById(@Query("id") id: number){
- return this.usersService.findById(id);
- }
- }
数据表间的关系
关系是在两个或多个表之间建立的关联,是基于每张表的公共字段,通常是主键和外键。
数据表之间有三种关系:
因此,在实体中定义关系可以使用相应的装饰器。
测试代码
users.controller.ts
- import {Get, Post, Body, Put, Delete, Query, Param, Controller} from '@nestjs/common';
- import { UsersService } from './users.service';
- @Controller('user')
- export class UsersController {
- constructor(private readonly usersService: UsersService){}
- // 查找指定用户
- @Get("find/:id")
- async findById(@Query("id") id: number){
- return this.usersService.findById(id);
- }
当我们运行代码时,数据库自动生成了users表。
而当我们在postman向服务器请求指定id的用户信息时,请求结果如下所示:
后台显示结果如下:
我们看到以上代码测试是正确的。
小结
本篇文章介绍了mysql和typeorm之间的关系,typeorm的配置,nest是如何通过typeorm连接数据库,以及简单的用户表数据查询。
其实笔者之前也用过 Sequelize ,现在想要尝试typeorm和nest的搭配,所以文章写的有些乱,建议诸位多加查看官方文档:《Nest官方文档》和《Typeorm官方文档》