TypeORM操作数据库
1. Nest集成TypeORM
- 由于datasource的配置是需要手动传入的,所以,TypeORM需要做成动态模块,支持根据传入的配置来动态产生模块内容。而动态模块的规范里就 3 种方法名: register、forRoot、forFeature。
- 用forRoot只需要注册一次,然后这个模块会在各处被使用。
npm install --save @nestjs/typeorm typeorm mysql2
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: 'hello-mysql',
entities: [],
synchronize: true,
}),
],
})
export class AppModule {}
2. 多级分类的场景
创建树形实体类
- 通过 @TreeChildren 声明的属性里存储着它的 children 节点,通过 @TreeParent 声明的属性里存储着它的 parent 节点。
- 并且这个 entity 要用 @Tree 声明。一般都是用 closure-table,或者 materialized-path。
- closure-table生成了两个表,在 city 表里保存着 city 记录之间的父子关系,通过 parentId 关联。在 city_closure 表里记录了也记录了父子关系。
- materialized-path只生成了一个表,只是这个表多了一个 mpath 字段。
// city.entity.ts
import { Column, CreateDateColumn, Entity, PrimaryGeneratedColumn, Tree, TreeChildren, TreeParent, UpdateDateColumn } from "typeorm";
@Entity()
@Tree('closure-table')
export class City {
@PrimaryGeneratedColumn()
id: number;
@Column({ default: 0 })
status: number;
@CreateDateColumn()
createDate: Date;
@UpdateDateColumn()
updateDate: Date;
@Column()
name: string;
@TreeChildren()
children: City[];
@TreeParent()
parent: City;
}
获取树形数据
@InjectEntityManager()
entityManager: EntityManager;
async findAll() {
return this.entityManager.getTreeRepository(City).findTrees();
}
获取树形数据的第一层级数据
@InjectEntityManager()
entityManager: EntityManager;
async findAll() {
return this.entityManager.getTreeRepository(City).findRoots();
}
findDescendantsTree查询某个节点的所有后代节点
@InjectEntityManager()
entityManager: EntityManager;
async findAll() {
const parent = await this.entityManager.findOne(City, { where: { name: '云南' } });
return this.entityManager.getTreeRepository(City).findDescendantsTree(parent)
}
findAncestorsTree查询某个节点的所有祖先节点
@InjectEntityManager()
entityManager: EntityManager;
async findAll() {
const parent = await this.entityManager.findOne(City, { where: { name: '云南' } });
return this.entityManager.getTreeRepository(City).findAncestorsTree(parent)
}
countAncestors 和 countDescendants 来计数返回层级数
@InjectEntityManager()
entityManager: EntityManager;
async findAll() {
const parent = await this.entityManager.findOne(City, { where: { name: '云南' } });
return this.entityManager.getTreeRepository(City).countAncestors(parent)
}
Prisma操作数据库
1. 基本使用
初始化项目
mkdir prisma-app
cd prisma-app
npm init -y
- 安装 typescript 相关的包:
npm install typescript ts-node @types/node --save-dev
- 创建 tsconfig.json
npx tsc --init
- 安装 prisma:
npm install prisma --save-dev
创建 schema 文件
- primsa init 创建 schema 文件
// 创建 mysql 数据库的 schema 文件
npx prisma init --datasource-provider mysql
- 修改 .env 文件里存储着连接信息
DATABASE_URL="mysql://root:root@localhost:3306/prisma_test"
数据建表
- 定义 model
model User {
id Int @id @default(autoincrement())
email String @unique
name String?
}
- 基于model生成 client 的代码
prisma migrate dev 根据 schema 文件生成 sql 并执行,还会生成 client 代码。
npx prisma migrate dev --name aaa
- 在 mysql workbench 里可以看到生成了 1 个表
2. Prisma 的命令
Prisma 的全部命令
- init:创建 schema 文件
- generate: 根据 shcema 文件生成 client 代码
- db:同步数据库和 schema
- migrate:生成数据表结构更新的 sql 文件
- studio:用于 CRUD 的图形化界面
- validate:检查 schema 文件的语法错误
- format:格式化 schema 文件
- version:版本信息
创建完 schema 文件,如何定义 model 呢?
可以执行 prisma db pull 把数据库里的表同步到 schema 文件。
prisma db pull
可以执行 prisma db push 把 schema 文件同步到了 database,并且生成了 client 代码。
prisma db push
数据迁移
- prisma migrate dev
会根据 schema 的变化生成 sql 文件,并执行这个 sql,还会生成 client 代码。
既创建了表,又插入了初始数据,还生成了 client。
prisma migrate dev --name init