前言,小编最近在学习NestJS系列相关知识,想把自己了解到的知识点作为笔记的同时也分享给大家,本篇涉及的是结合TypeORM框架并连接MySQL数据库的知识,如果有哪里写的不好的话还恳请各位掘友批评指正谢谢,小编将不胜感激,闲话不多说,我们直接步入正题吧...
-
[系列阅读 ]
-
[ 源代码地址] - GitHub仓库地址
TypeORM和MySQL在NestJS应用中扮演不同的角色,但它们共同工作以实现数据库操作。我们先简单理解下它们各自的作用和关系:
MySQL:
-
角色:MySQL是一个关系型数据库管理系统。
-
作用:
- 存储和管理应用程序的数据
- 提供数据的持久化
- 支持复杂的查询和数据操作
- 确保数据的一致性和完整性
TypeORM:
-
角色:TypeORM是一个对象关系映射(ORM)库。
-
作用:
- 在应用程序代码和数据库之间架起桥梁
- 将JavaScript/TypeScript对象映射到数据库表
- 提供一种面向对象的方式来操作数据库
- 简化数据库操作,无需直接编写SQL查询
- 支持多种数据库系统,包括MySQL
关系:
- 抽象层:TypeORM作为一个抽象层,位于我们的NestJS应用和MySQL数据库之间。
- 数据映射:TypeORM将我们在NestJS中定义的实体(Entities)映射到MySQL的表。
- 查询构建:TypeORM提供了一个查询构建器,允许我们用TypeScript编写类似SQL的查询,然后将其转换为MySQL可以理解的SQL语句。
- 数据库连接:TypeORM管理与MySQL数据库的连接,处理连接池等底层细节。
- 数据类型转换:TypeORM负责在JavaScript/TypeScript类型和MySQL数据类型之间进行转换。
- 迁移支持:TypeORM提供了数据库迁移工具,可以帮助我们管理数据库架构的变更。
项目中引入 typeorm 的项目依赖:
npm install --save @nestjs/typeorm typeorm mysql2
推荐一个数据库的可视化工具
开始连接数据库服务
注意上图中的端口和密码等,是我们安装mysql时设置的,比如图中小编的端口为3307,是在下图时安装配置时小编改的
连接成功显示如下
新建一个student数据库
初始化 typeorm 配置
生成一个 dbTest 的 curd 项目模块
自动加载实体的实现
定义 dbTest 中实体文件的内容
关联实体
运行项目并查看数据库发现创建成功,student数据库自动加载并创建了我们刚刚自定义的实体
根据上述实体的实现不难发现:在 NestJS 和 TypeORM 的上下文中,实体(Entity)是一个非常重要的概念。那么实体是什么呢,以及如何在 NestJS 中使用它们,接下来将继续解析
实体(Entity)是什么?
- 定义:实体是一个映射到数据库表的类。
作用:它代表了数据库中的一个表,类的属性对应表的列。- 特点:实体类通常包含基本的属性和方法,用于描述数据结构和行为。
在 NestJS 中如何使用实体:
- 创建实体类:
import { Entity, Column, PrimaryGeneratedColumn } from 'typeorm';
@Entity()
export class User {
@PrimaryGeneratedColumn() //自增属性,即对应多行数据时id会自动自增
id: number;
@Column() //定义列属性,表明它对应数据库表中的一列
firstName: string;
@Column()
lastName: string;
@Column({ default: true })
isActive: boolean;
}
- 在模块中导入实体:
import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';
import { User } from './user.entity';
@Module({
imports: [TypeOrmModule.forFeature([User])],
// ...
})
export class UsersModule {}
- 在服务中使用实体:
import { Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { User } from './user.entity';
@Injectable()
export class UsersService {
constructor(
@InjectRepository(User)
private usersRepository: Repository<User>,
) {}
findAll(): Promise<User[]> {
return this.usersRepository.find();
}
findOne(id: number): Promise<User> {
return this.usersRepository.findOne({ where: { id } });
}
async create(user: User): Promise<User> {
return this.usersRepository.save(user);
}
// ... 其他方法
}
-
使用装饰器:
- @Entity(): 标记一个类为实体。
- @PrimaryGeneratedColumn(): 定义主键并自动生成。
- @Column(): 定义普通列。
- @CreateDateColumn(), @UpdateDateColumn(): 自动管理创建和更新时间。
- @OneToMany(), @ManyToOne(), @ManyToMany(): 定义关系。
上述内容的知识点的关系可以总结为:我们首先使用 Database Client 插件连接了 mysql 服务,提供了可视化工具供我们使用,接着在项目中使用 typeorm 连接了 mysql,在运行项目时将项目中的实体类的相关信息映射到我们连接的 student 数据库,从而对student数据库里面的数据库表进行一些 curd 的操作
补充:小编发现自己有点搞混实体和DTO的区别和作用了,查阅资料后补如下
-
目的和使用场景:
- DTO:主要用于数据传输,定义了客户端和服务器之间如何传输数据。它用于 API 层,处理请求和响应。
- 实体:代表数据库中的表结构,用于数据持久化。它在数据访问层使用,与数据库交互。
-
结构和内容:
- DTO:通常只包含客户端需要的数据字段,可能是实体的一个子集或组合。
- 实体:包含数据库表的完整结构,包括所有列和关系。
-
装饰器:
- DTO:主要使用验证装饰器(如 class-validator 中的 @IsNotEmpty(), @IsEmail() 等)。
- 实体:使用 ORM 相关的装饰器(如 @Entity(), @Column(), @PrimaryGeneratedColumn() 等)。
-
业务逻辑:
- DTO:通常不包含业务逻辑,主要用于数据验证和传输。
- 实体:可能包含一些与数据相关的业务逻辑和方法。
-
生命周期:
- DTO:在单个请求/响应周期中使用,不持久化。
- 实体:与数据库记录的生命周期相匹配,可以被持久化。
-
灵活性:
- DTO:更加灵活,可以根据 API 需求自由定义。
- 实体:结构通常需要与数据库模式保持一致。
-
验证和转换:
- DTO:常用于输入验证和数据转换。
- 实体:主要关注数据持久化和检索。
-
安全性:
- DTO:可以隐藏敏感信息,只暴露必要的字段给客户端。
- 实体:包含所有数据库字段,包括可能的敏感信息。
-
版本控制:
- DTO:可以轻松适应 API 版本变化,不影响数据库结构。
- 实体:变更可能需要数据库迁移。
示例对比:
DTO:
export class CreateUserDto {
@IsNotEmpty()
@IsString()
readonly name: string;
@IsEmail()
readonly email: string;
@IsNotEmpty()
@MinLength(6)
readonly password: string;
}
实体:
@Entity()
export class User {
@PrimaryGeneratedColumn()
id: number;
@Column()
name: string;
@Column({ unique: true })
email: string;
@Column()
password: string;
@Column({ default: true })
isActive: boolean;
@CreateDateColumn()
createdAt: Date;
@UpdateDateColumn()
updatedAt: Date;
}
总结:
DTO 和实体在 NestJS 应用中扮演不同但互补的角色。DTO 专注于数据传输和 API 交互,而实体则关注数据持久化和数据库交互。使用这两种结构可以帮助你构建更清晰、更安全、更易维护的应用程序架构。