# 在项目中使用 TypeORM
TypeORM 官网介绍
TypeORM 是一个 ORM 框架,它可以运行在 NodeJS、Browser、Cordova、PhoneGap、Ionic、React Native、Expo 和 Electron 平台上,可以与 TypeScript 和 JavaScript (ES5,ES6,ES7,ES8) 一起使用。 它的目标是始终支持最新的 JavaScript 特性并提供额外的特性以帮助你开发任何使用数据库的(不管是只有几张表的小型应用还是拥有多数据库的大型企业应用)应用程序。
不同于现有的所有其他 JavaScript ORM 框架,TypeORM 支持 Active Record 和 Data Mapper 模式,这意味着你可以以最高效的方式编写高质量的、松耦合的、可扩展的、可维护的应用程序。
个人理解作用是
- 可以链接不同的数据库,MySQL、PostgreSQL、MongoDB...
2. 可以在项目中写入实体然后映射到数据库中 (大白话的意思就是可以在项目中写数据表,然后自动映射到数据库中) - TypeORM 中提供了很多 api 去 操控数据库。
这里使用的是 MySQL 所以也需要下载 MySQL 的依赖包
# 安装依赖
yarn add @nestjs/typeorm typeorm mysql2
在 app.module.ts 中导入
//app.module.ts | |
import { Module } from '@nestjs/common'; | |
import { AppController } from './app.controller'; | |
import { AppService } from './app.service'; | |
import { TypeOrmModule } from '@nestjs/typeorm';// 引入 typeorm | |
import { UsersModule } from './users/users.module'; | |
@Module({ | |
controllers: [AppController,], | |
providers: [AppService], | |
imports: [TypeOrmModule.forRoot({ | |
"type": "mysql", | |
"host": "localhost",// 数据库地址 | |
"port": 3306,// 数据库端口 | |
"username": "root", | |
"password": "9999999", | |
"database": "blog",// 数据库名称 | |
"retryAttempts":10,// 连接数据库的尝试次数(默认:10) | |
"autoLoadEntities": true,// 如果 true, 实体将被自动加载 (默认: false) | |
"synchronize": true | |
}),UsersModule], | |
}) | |
export class AppModule {} |
# 实体
官网介绍:
实体是一个映射到数据库表(或使用 MongoDB 时的集合)的类。 你可以通过定义一个新类来创建一个实体,并用 @Entity () 来标记:
个人理解:
实体是相当于数据库中的表,可以通过 typeorm 提供的 一些装饰器来创建每一列,每张表都需要一个 @Entity () 装饰器来标记
import { Entity, PrimaryGeneratedColumn, Column } from "typeorm"; | |
@Entity() | |
export class Users { | |
@PrimaryGeneratedColumn() | |
id: number; | |
@Column() | |
firstName: string; | |
@Column() | |
lastName: string; | |
@Column() | |
isActive: boolean; | |
} |
将会创建
+-------------+--------------+----------------------------+
| users |
+-------------+--------------+----------------------------+
| id | int(11) | PRIMARY KEY AUTO_INCREMENT |
| firstName | varchar(255) | |
| lastName | varchar(255) | |
| isActive | boolean | |
+-------------+--------------+----------------------------+
`
举例子 创建用户模块 并且写入用户实体,生成用户表
使用命令创建
- nest g co
- nest g s
- nset g m
创建完文件夹后中,users 文件下 创建 users.entities 文件
//users.entities.ts | |
import { Column, CreateDateColumn, UpdateDateColumn, Entity, PrimaryGeneratedColumn } from "typeorm" | |
@Entity() | |
export class Users { | |
// 使用 @PrimaryGeneratedColumn () | |
// @PrimaryGeneratedColumn ('uuid') 自动生成 uuid | |
@PrimaryGeneratedColumn('uuid') | |
id: string | |
@Column({ | |
type: 'varchar',// 字段类型 | |
comment: '用户名',// 备注 | |
nullable: false,// 是否可以为 null 默认是 false | |
length: 128,// 长度 | |
}) | |
username: string// 字段名 | |
@Column({ | |
type: 'varchar', | |
comment: '用户昵称', | |
length: 128 | |
}) | |
user_nickname: string | |
@Column({ | |
type: 'varchar', | |
comment: '用户密码', | |
length: 64 | |
}) | |
password: string | |
@Column({ | |
type: 'varchar', | |
comment: '用户手机号', | |
length: 11 | |
}) | |
phone: number | |
@Column({ | |
nullable: true, | |
type: 'varchar', | |
comment: '用户头像', | |
length: 128, | |
default:"xxx" | |
}) | |
avatar: string | |
// 自动为实体插入日期。无需设置此列,该值将自动设置。 | |
@CreateDateColumn() | |
createTime: Date; | |
// 在每次调用实体管理器或存储库的 save 时,自动更新实体日期。无需设置此列,该值将自动设置。 | |
@UpdateDateColumn() | |
updateTime: Date; | |
} |
注意:写完实体后 别忘记在 users.module.ts 文件中导入并使用 TypeOrmModule.forFeature ([]) 进行注册
<!--users.module.ts--> | |
import { Module } from '@nestjs/common'; | |
// 导入 TypeOrmModule | |
import { TypeOrmModule } from '@nestjs/typeorm'; | |
import { Users } from './users.entities'; | |
import { UsersController } from './users.controller'; | |
import { UsersService } from './users.service'; | |
//TypeOrmModule.forFeature 注册实体 Users | |
// TypeOrmModule.forFeature([ArticleEntities]) | |
@Module({ imports:[TypeOrmModule.forFeature([Users])], | |
controllers: [UsersController],providers:[UsersService]}) | |
export class UsersModule {} |
想了解更多实体中的装饰器,可以去 TypeORM 官网,点击链接跳转 https://typeorm.bootcss.com/entities
# 链接多个数据库
注意:
1、链接多个数据库时,不写 name 属性,name 默认是 defaul
2、需要注意每个数据库的 name 不能为空或者是重复
//app.module.ts | |
import { Module } from '@nestjs/common'; | |
import { AppController } from './app.controller'; | |
import { AppService } from './app.service'; | |
import { TypeOrmModule } from '@nestjs/typeorm';// 引入 typeorm | |
// 子模块加载 | |
import { UsersModule } from './users/users.module'; | |
const defaultOptions = { | |
type: 'mysql',// 数据库类型 | |
port: 5432,// 端口 | |
username: 'user',// 登录名 | |
password: 'password'// 密码 | |
synchronize: true, | |
}; | |
@Module({ | |
imports: [ | |
TypeOrmModule.forRoot({ | |
...defaultOptions, | |
database: 'blog',// 数据库名称 | |
name:"data1", | |
host: 'user_db_host',// 数据库地址 | |
}), | |
TypeOrmModule.forRoot({ | |
...defaultOptions, | |
database: 'blog1',// 数据库名称 | |
name: 'data2',// | |
host: 'album_db_host',// 数据库地址 | |
}), | |
UsersModule | |
], | |
}) | |
export class AppModule {} |
注意:
1、链接多个数据库时子模块中导入的实体 需要标明是哪个数据库
<!--users.module.ts--> | |
import { Module } from '@nestjs/common'; | |
import { TypeOrmModule } from '@nestjs/typeorm'; | |
import { Users } from './users.entities'; | |
import { UsersController } from './users.controller'; | |
import { UsersService } from './users.service'; | |
// 注册实体 Users | |
// TypeOrmModule.forFeature ([ArticleEntities],' 数据库 name') | |
@Module({ imports:[TypeOrmModule.forFeature([Users],'data1')], | |
controllers: [UsersController],providers:[UsersService]}) | |
export class UsersModule {} |
操作数据库
利用 TypeORM 提供的一些 api 去操控数据库
如:
find()
findOne()
save()
remove()
...
例:
//users.service.ts | |
import { HttpCode, HttpStatus, Injectable, NotFoundException } from '@nestjs/common'; | |
import { InjectRepository } from '@nestjs/typeorm'; | |
import { Repository } from 'typeorm'; | |
import { User } from './entities/user.entities'; | |
let status = { | |
success: { | |
code: HttpStatus.OK, | |
message: "操作成功" | |
} | |
}; | |
@Injectable() | |
export class UsersService { | |
constructor( | |
// 用 @InjectRepository () 装饰器将 UsersRepository 注入到 UsersService 中 | |
@InjectRepository(User) | |
private readonly UsersRepository: Repository<User> | |
) { } | |
// 查询全部用户 | |
findAll() { | |
return this.UsersRepository.find() | |
} | |
// 根据 id 查询用户 | |
async findOne(id: string) { | |
const user = await this.UsersRepository.findOne({ where: { id } }) | |
if (!user) { | |
throw new NotFoundException(`user #${id} is not found`) | |
} | |
return user | |
} | |
// 创建用户 | |
async create(CreateUserDto: CreateUserDto) { | |
let { username } = CreateUserDto | |
const name = await this.UsersRepository.findOne({ where: { username } }) | |
if (name) { | |
return { | |
code: HttpStatus.UNPROCESSABLE_ENTITY, | |
message: "用戶名已存在" | |
} | |
} | |
// 创建用户 | |
const user = this.UsersRepository.create(CreateUserDto) | |
try { | |
await this.UsersRepository.save(user) | |
} catch (error) { | |
return { | |
code: HttpStatus.UNPROCESSABLE_ENTITY, | |
message: error.driverError.sqlMessage | |
} | |
} | |
return status.success | |
} | |
// 根据用户 id 删除用户 | |
async remove(id: string) { | |
const user = await this.UsersRepository.findOne({ where: { id } }) | |
const res = await this.UsersRepository.remove(user) | |
if (res) { | |
return status.success | |
} | |
} | |
} |
增 | |
save(user) 创建:返回该数据的所有字段 | |
insert(user) 快速插入一条数据,插入成功:返回插入实体,与save方法不同的是,它不执行级联、关系和其他操作。 | |
删 | |
remove(user) 删除:返回该数据的可见字段 | |
softRemove(user); 拉黑:返回该数据的可见字段,该删除实体必须拥有@DeleteDateColumn()字段,被拉黑的用户还存在数据库中,但无法被find查找到,会在@DeleteDateColumn()字段中添加删除时间,可使用recover恢复 | |
改 | |
update(id, user) 更新:返回更新实体,不是该数据的字段 | |
恢复 | |
recover({ id }) 恢复:返回id,将被softRemove删除(拉黑)的用户恢复,恢复成功后可以被find查找到 | |
查找全部 | |
find() | |
find({id:9}) 条件查找,写法一,找不到返回空对象 | |
find({where:{id:10}}) 条件查找,写法二,找不到返回空对象 | |
findAndCount() 返回数据和总的条数 | |
查找一个 | |
findOne(id); 根据ID查找,找不到返回undefined | |
findOne({ where: { username } }); 条件查找,找不到返回undefined | |
根据ID查找一个或多个 | |
findByIds([1,2,3]); 查找n个,全部查找不到返回空数组,找到就返回找到的 | |
其他 | |
hasId(new UsersEntity()) 检测实体是否有合成ID,返回布尔值 | |
getId(new UsersEntity()) 获取实体的合成ID,获取不到返回undefined | |
create({username: 'admin12345', password: '123456',}) 创建一个实体,需要调用save保存 | |
count({ status: 1 }) 计数,返回数量,无返回0 | |
increment({ id }, 'age', 2); 增加,给条件为id的数据的age字段增加2,成功返回改变实体 | |
decrement({ id }, 'age', 2) 减少,给条件为id的数据的age字段增加2,成功返回改变实体 | |
谨用 | |
findOneOrFail(id) 找不到直接报500错误,无法使用过滤器拦截错误,不要使用 | |
clear() 清空该数据表,谨用!!! |
我们形形色色,像无数条河里的水各自流淌,演绎出不一样的故事后,还是要以一样的姿态走上死亡这条路,一切伪装、恐惧、欣喜、慌张,都会有渐渐淡去的那一天。
————《我的郁金香小姐》