如果小伙伴还不会使用nestjs
连接数据库的话 可以看我的上一篇文章 NestJs使用连接mysql企业级开发规范
关系
关系是指两个或多个表之间的联系。关系基于每个表中的常规字段,通常包含主键和外键。关系有三种:
名称 | 说明 |
一对一 | 主表中的每一行在外部表中有且仅有一个对应行。使用@OneToOne()装饰器来定义这种类型的关系 |
一对多/多对一 | 主表中的每一行在外部表中有一个或多的对应行。使用@OneToMany()和@ManyToOne()装饰器来定义这种类型的关系 |
多对多 | 主表中的每一行在外部表中有多个对应行,外部表中的每个记录在主表中也有多个行。使用@ManyToMany()装饰器来定义这种类型的关系 |
user.entity.ts
import {
Column,
Entity,
PrimaryGeneratedColumn,
} from 'typeorm';
@Entity() // 最终实现实体类
export class User {
@PrimaryGeneratedColumn()
id: number;
@Column()
username: string;
@Column()
password: string;
}
可以使用navicat
查看创建的user表
再来创建一个profile.entity.ts
import {
Column,
Entity,
JoinColumn,
OneToOne,
PrimaryGeneratedColumn,
} from 'typeorm';
@Entity()
export class Profile {
@PrimaryGeneratedColumn()
id: number;
@Column()
gender: number;
@Column()
photo: string;
@Column()
address: string;
}
再来创建一个roles.entity.ts
import { Column, Entity, ManyToMany, PrimaryGeneratedColumn } from 'typeorm';
@Entity()
export class Roles {
@PrimaryGeneratedColumn()
id: number;
@Column()
name: string;
}
再来创建一个logs.entity.ts
import {
Column,
Entity,
JoinColumn,
ManyToOne,
PrimaryGeneratedColumn,
} from 'typeorm';
@Entity()
export class Logs {
@PrimaryGeneratedColumn()
id: number;
@Column()
path: string;
@Column()
methods: string;
@Column()
data: string;
@Column()
result: number;
}
创建完之后别忘记把这个四个实体 添加到app.module.ts
中
import { Module } from '@nestjs/common';
import { UserModule } from './user/user.module';
import { ConfigModule, ConfigService } from '@nestjs/config';
import * as dotenv from 'dotenv';
import * as Joi from 'joi';
import { TypeOrmModule, TypeOrmModuleOptions } from '@nestjs/typeorm';
import { ConfigEnum } from './enum/config.enum';
import { User } from './user/user.entity';
import { Profile } from './user/profile.entity';
import { Logs } from './logs/logs.entity';
import { Roles } from './roles/roles.entity';
const envFilePath = `.env.${process.env.NODE_ENV || `development`}`;
@Module({
imports: [
ConfigModule.forRoot({
isGlobal: true,
envFilePath,
load: [() => dotenv.config({ path: '.env' })],
validationSchema: Joi.object({
NODE_ENV: Joi.string()
.valid('development', 'production')
.default('development'),
DB_PORT: Joi.number().default(3306),
DB_HOST: Joi.string().ip(),
DB_TYPE: Joi.string().valid('mysql', 'postgres'),
DB_DATABASE: Joi.string().required(),
DB_USERNAME: Joi.string().required(),
DB_PASSWORD: Joi.string().required(),
DB_SYNC: Joi.boolean().default(false),
}),
}),
TypeOrmModule.forRootAsync({
imports: [ConfigModule],
inject: [ConfigService],
useFactory: (configService: ConfigService) =>
({
type: configService.get(ConfigEnum.DB_TYPE),
host: configService.get(ConfigEnum.DB_HOST),
port: configService.get(ConfigEnum.DB_PORT),
username: configService.get(ConfigEnum.DB_USERNAME),
password: configService.get(ConfigEnum.DB_PASSWORD),
database: configService.get(ConfigEnum.DB_DATABASE),
entities: [User, Profile, Logs, Roles],
// 同步本地的schema与数据库 -> 初始化的时候去使用
synchronize: configService.get(ConfigEnum.DB_SYNC),
logging: process.env.NODE_ENV === 'development',
// logging: ['error'],
} as TypeOrmModuleOptions),
}),
// TypeOrmModule.forRoot({
// type: 'mysql',
// host: 'localhost',
// port: 3306,
// username: 'root',
// password: 'example',
// database: 'testdb',
// entities: [],
// // 同步本地的schema与数据库 -> 初始化的时候去使用
// synchronize: true,
// logging: ['error'],
// }),
UserModule,
],
controllers: [],
providers: [],
})
export class AppModule {}
这样我们就创建好了表
接下来我们来创建表和表之间的关系
通过这个er图我们很容易看出表与表之间的关系。
接下来我们现在profile.entity.ts
中创创建和user表的关系
一对一
一对一是一种 A 只包含一个 B 实例,而 B 只包含一个 A 实例的关系。 我们以User和Profile实体为例。
用户只能拥有一个配置文件,并且一个配置文件仅由一个用户拥有。
import {
Column,
Entity,
JoinColumn,
OneToOne,
PrimaryGeneratedColumn,
} from 'typeorm';
import { User } from './user.entity';
@Entity()
export class Profile {
@PrimaryGeneratedColumn()
id: number;
@Column()
gender: number;
@Column()
photo: string;
@Column()
address: string;
@OneToOne(() => User)
@JoinColumn() // 会默认使用小驼峰 创建一个字段进行连接
// @JoinColumn({name:'userId'})
user: User;
}
这里我们将@OneToOne添加到user并将目标关系类型指定为User。 我们还添加了@JoinColumn,这是必选项并且只能在关系的一侧设置。 你设置@JoinColumn的哪一方,哪一方的表将包含一个"relation id"和目标实体表的外键。
同样,@JoinColumn必须仅设置在关系的一侧且必须在数据库表中具有外键的一侧。
@OneToOne(() => User)
// 使用函数 我们在需要的地方再次调用
// 我们并不需要关系User类里面的内容
多对一/一对多的关系
多对一/一对多是指 A 包含多个 B 实例的关系,但 B 只包含一个 A 实例。 让我们以User 和 Logs实体为例。 User 可以拥有多张 Logs,但每张 Log 仅由一位 user 拥有。
import {
Column,
Entity,
PrimaryGeneratedColumn,
OneToMany,
ManyToMany,
JoinTable,
OneToOne,
} from 'typeorm';
import { Logs } from '../logs/logs.entity';
@Entity()
export class User {
@PrimaryGeneratedColumn()
id: number;
@Column()
username: string;
@Column()
password: string;
// typescript -> 数据库 关联关系 Mapping
@OneToMany(() => Logs, (logs) => logs.user)
logs: Logs[];
}
logs.entity.ts
import {
Column,
Entity,
JoinColumn,
ManyToOne,
PrimaryGeneratedColumn,
} from 'typeorm';
import { User } from '../user/user.entity';
@Entity()
export class Logs {
@PrimaryGeneratedColumn()
id: number;
@Column()
path: string;
@Column()
methods: string;
@Column()
data: string;
@Column()
result: number;
// typescript 数据库 关联关系
@ManyToOne(() => User, (user) => user.logs)
// user.logs 建立 OneToMany 的关系
@JoinColumn()
user: User;
}
这里我们将@OneToMany添加到logs属性中,并将目标关系类型指定为Logs。 你可以在@ManyToOne / @OneToMany关系中省略@JoinColumn,除非你需要自定义关联列在数据库中的名称。 @ManyToOne可以单独使用,但@OneToMany必须搭配@ManyToOne使用。 如果你想使用@OneToMany,则需要@ManyToOne。 在你设置@ManyToOne的地方,相关实体将有"关联 id"和外键。
多对多的关系
多对多是一种 A 包含多个 B 实例,而 B 包含多个 A 实例的关系。 我们以User和 Roels实体为例。
user.entity.ts
import {
Column,
Entity,
PrimaryGeneratedColumn,
OneToMany,
ManyToMany,
JoinTable,
OneToOne,
} from 'typeorm';
import { Logs } from '../logs/logs.entity';
import { Roles } from '../roles/roles.entity';
import { Profile } from './profile.entity';
@Entity()
export class User {
@PrimaryGeneratedColumn()
id: number;
@Column()
username: string;
@Column()
password: string;
// typescript -> 数据库 关联关系 Mapping
@OneToMany(() => Logs, (logs) => logs.user)
logs: Logs[];
@ManyToMany(() => Roles, (roles) => roles.users)
// 建立中间表
@JoinTable({ name: 'users_roles' })
roles: Roles[];
@OneToOne(() => Profile, (profile) => profile.user)
profile: Profile;
}
roles.entity.ts
import { Column, Entity, ManyToMany, PrimaryGeneratedColumn } from 'typeorm';
import { User } from '../user/user.entity';
@Entity()
export class Roles {
@PrimaryGeneratedColumn()
id: number;
@Column()
name: string;
@ManyToMany(() => User, (user) => user.roles)
users: User[];
}
到此为止 我们介绍了 一对一,一对多,多对多的关系,当然也都是从0到1 创建表的过程。恭喜,你成功进步了一大截。那么企业中都是0到1的场景吗?当然不是,那要是在原有的库上增加数据我们该怎么办呢?
接下来我们要介绍 旧项目中已有数据库我们怎么使用TypeORM
那么我们需要了解一下一个库:typeorm-model-generator
局部安装
pnpm i -D typeorm-model-generator
然后 使用 package.json
新增一个命令
"generate:models": "typeorm-model-generator -h 127.0.0.1 -p 3306 -d testdb -u root -x 123456 -e mysql -o ./src/entities"
开始执行
项目中会生成一个 entities
文件夹
注意
如果是旧项目 还是放在 entities 里面,后面新项目还是单独放
启动项目,启动成功,之前库也都存在了。
下面一篇文章介绍 创建实体功能NestJs使用MySQL创建多个实体