跳到主要内容

将数据库生成数据模型

一、关于 typeorm-model-generator 的介绍

typeorm-model-generator 简单点就是将现有的数据库中的表使用命令的方式自动生成 typeorm 的数据模型(注意前提是数据库要有表)

目前支持的数据库有

  • Microsoft SQL Server
  • PostgreSQL
  • MySQL
  • MariaDB
  • Oracle Database
  • SQLite

二、使用方式

1、全局安装模块(也可以使用 npx,但是这种方式生成数据模型的时候会有点慢)

npm i -g typeorm-model-generator

2、新创建一个文件夹

3、生成 package.json 的文件

4、在 package.json 文件下的 scripts 配置命令

"scripts": {
"db": "rm -rf entities & npx typeorm-model-generator -h localhost -d testdabase -p 3306 -u root -x root -e mysql -o entities --noConfig true --ce pascal --cp camel"
}
rm -rf entities表示先删除文件夹entities
npx typeorm-model-generator如果全局安装了就不需要加npx没有全局安装就加上去
-h localhost -d 数据库名字 -p 端口 -u 用户名 -x 密码 -e 数据库类型
-o entities表示输出到指定的文件夹
--noConfig true表示不生成ormconfig.json和tsconfig.json文件
--ce pascal表示将类名转换首字母是大写的驼峰命名
--cp camel表示将数据库中的字段比如create_at转换为createAt
-a表示会继承一个BaseEntity的类,根据自己需求加

5、直接运行命令就可以在 entities 文件夹下生成全部的数据模型(目前格式有点丑,需要自己手动调整下)

npm run db

三、在 nestjs 中使用

虽然 nestjs/typeorm 中连接 mysql 的 ormconfig.json 中有个字段 synchronize: true 表示自动会根据模型生成表,但是我个人觉得仅仅适合个人在开发中玩玩,在团队开发中可能有专门的 db 管理数据库的,不可能让你直接代码同步生产数据表的,所以我们可以借用上面的方式数据库同步生成模型

1、使用 nest new demo 创建一个项目

2、在 package.json 中配置命令

"scripts": {
"db": "rm -rf entities & npx typeorm-model-generator -h localhost -d testdabase -p 3306 -u root -x root -e mysql -o entities --noConfig true --ce pascal --cp camel"
}

3、手动将生成的模型改为 xx.entity.ts

四、一个多表操作的示例

1、用户表的 sql 语句

CREATE TABLE `user` (
`id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键id',
`uuid` varchar(150) COLLATE utf8_bin NOT NULL COMMENT 'uuid主键',
`name` varchar(100) COLLATE utf8_bin NOT NULL COMMENT '姓名',
`password` varchar(255) COLLATE utf8_bin NOT NULL COMMENT '密码',
`email` varchar(100) COLLATE utf8_bin DEFAULT NULL COMMENT '邮箱',
`mobile` varchar(11) COLLATE utf8_bin DEFAULT NULL COMMENT '手机号码',
`gender` tinyint(4) DEFAULT '0' COMMENT '性别',
`create_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`update_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
PRIMARY KEY (`id`),
UNIQUE KEY `uuid` (`uuid`),
UNIQUE KEY `name` (`name`)
) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8 COLLATE=utf8_bin

2、用户扩展表的 sql

CREATE TABLE `user_extend` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`QQ` varchar(255) DEFAULT NULL,
`address` varchar(255) DEFAULT NULL,
`user_id` int(11) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8

3、在 nestjs 项目中创建一个 user.module 及基本文件

  • nest g mo user
  • nest g controller user
  • nest g service user

4、运行命令让数据表生产数据模型

user.entity.ts

import { BaseEntity, Column, Entity, PrimaryGeneratedColumn } from "typeorm";

@Entity("user", { schema: "koa" })
export class UserEntity extends BaseEntity {
@PrimaryGeneratedColumn({
type: "int",
name: "id",
})
id: number;

@Column("varchar", {
nullable: false,
unique: true,
length: 150,
name: "uuid",
generated: "uuid",
})
uuid: string;

@Column("varchar", {
nullable: false,
unique: true,
length: 100,
name: "name",
})
name: string;

@Column("varchar", {
nullable: false,
name: "password",
})
password: string;

@Column("varchar", {
nullable: true,
length: 100,
name: "email",
})
email: string | null;

@Column("varchar", {
nullable: true,
length: 11,
name: "mobile",
})
mobile: string | null;

@Column("tinyint", {
nullable: true,
default: () => 0,
name: "gender",
})
gender: number | null;

@Column("timestamp", {
nullable: false,
default: () => "CURRENT_TIMESTAMP",
name: "create_at",
})
createAt: Date;

@Column("timestamp", {
nullable: false,
default: () => "CURRENT_TIMESTAMP",
name: "update_at",
})
updateAt: Date;
}

user.extend.entity.ts

import { BaseEntity, Column, Entity, PrimaryGeneratedColumn } from "typeorm";

@Entity("user_extend", { schema: "koa" })
export class UserExtendEntity extends BaseEntity {
@PrimaryGeneratedColumn({
type: "int",
name: "id",
})
id: number;

@Column("varchar", {
nullable: true,
name: "QQ",
})
qq: string | null;

@Column("varchar", {
nullable: true,
name: "address",
})
address: string | null;

@Column("int", {
nullable: true,
name: "user_id",
})
userId: number | null;
}

5、根据不同的 entity 文件创建不同的 dto 文件

export class CreateUserDto {
readonly name: string;
readonly password: string;
readonly email?: string;
readonly mobile?: string;
readonly gender?: number;
}
export class CreateUserExtendDto {
readonly QQ?: string;
readonly address?: string;
}

6、在控制器中使用

...

@Post()
async create(@Body() data: Extract<CreateUserDto, CreateUserExtendDto>) {
return this.userService.create(data);
}

...

7、在服务层中使用

async create(data: Extract<CreateUserDto, CreateUserExtendDto>) {
const { name, password, email, mobile, gender, qq, address } = data;
const user = await this.userRepository.save({
name,
password,
email,
mobile,
gender,
});
await this.userExtendRepository.save({ userId: user.id, qq, address });
return '创建成功';
}

8、涉及多表操作可以将上面的代码加个事务上去

async create(data: Extract<CreateUserDto, CreateUserExtendDto>) {
const { name, password, email, mobile, gender, qq, address } = data;
const connection = getConnection();
const queryRunner = connection.createQueryRunner();
await queryRunner.connect();
await queryRunner.startTransaction();
try {
const user = await queryRunner.manager.insert<UserEntity>(UserEntity, {
name,
password,
email,
mobile,
gender,
});
Logger.log(JSON.stringify(user), '插入user的数据');
const userId = user.identifiers[0].id;
await queryRunner.manager.insert<UserExtendEntity>(UserExtendEntity, {
userId,
qq,
address,
});
await await queryRunner.commitTransaction();
return '创建成功';
} catch (e) {
await queryRunner.rollbackTransaction();
throw new BadRequestException('创建失败');
}
}

async findAll() {
return this.userRepository.find();
}

五、另外一种方式实现事务 这次将事务直接加到控制层

1、控制层的代码

@Post()
@Transaction()
async create(
@Body() data: Extract<CreateUserDto, CreateUserExtendDto>,
@TransactionManager() manager: EntityManager,
) {
return this.userService.create(data, manager);
}

2、在服务层中使用

async create(
data: Extract<CreateUserDto, CreateUserExtendDto>,
manager: EntityManager,
) {
const { name, password, email, mobile, gender, qq, address } = data;
const user: { [propName: string]: any } = await manager.save(UserEntity, {
name,
password,
email,
mobile,
gender,
});
Logger.log(JSON.stringify(user), '当前用户');
// throw new Error('错误了')
await manager.save(UserExtendEntity, {
userId: user.id,
qq,
address,
});
return '创建成功';

}