将数据库生成数据模型
一、关于 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 '创建成功';
}