TypeORM 启动!

启动!

ORM 是 **<u><font style="color:rgb(37, 41, 51);">Object Relational Mapping</font></u>**,对象关系映射。也就是说把关系型数据库的表映射成面向对象的 class,表的字段映射成对象的属性映射,表与表的关联映射成属性的关联。可实现在代码中爽滑操作数据库!

<u><font style="color:rgb(37, 41, 51);">DataSource</font></u> 里管理着数据库连接配置,数据库驱动包,调用它的 intialize 方法会创建和 mysql 的连接

连接创建的时候,如果指定了 <font style="color:rgb(37, 41, 51);">synchronize</font>,会根据 Entitiy 生成建表 sql。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
import { DataSource } from "typeorm";
import { User } from "./entity/User";
import { Aaa } from "./entity/Aaa";

export const AppDataSource = new DataSource({
type: "mysql",
host: "localhost",
port: 3306,
username: "root",
password: "123456",
database: "practice",
synchronize: true,
logging: true,
entities: [User, Aaa],
migrations: [],
subscribers: [],
connectorPackage: "mysql2",
extra: {
authPlugin: "sha256_password",
},
});

Entity 里通过 <font style="color:rgb(37, 41, 51);">@Entity</font> 指定和数据库表的映射,通过 <font style="color:rgb(37, 41, 51);">@PrimaryGeneratedColumn</font><font style="color:rgb(37, 41, 51);">@Column</font> 指定和表的字段的映射。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import { Column, Entity, PrimaryGeneratedColumn } from "typeorm";

@Entity({ name: "t_aaa" })
export class Aaa {
@PrimaryGeneratedColumn({ comment: "这是id" })
id: number;
@Column({
name: "a_aa",
type: "text",
comment: "这是aaa",
})
aaa: string;
@Column({ type: "varchar", length: 10, unique: true, nullable: false })
bbb: string;
@Column({ type: "double" })
ccc: number;
}

对 Entity 做增删改查通过 EntityManager 的 <font style="color:rgb(37, 41, 51);">save、delete、find、createQueryBuilder</font> 等方法。

如果只是对单个 Entity 做 CRUD,那可以先 <font style="color:rgb(37, 41, 51);">getRepository</font> 拿到对具体 Entity 操作的工具类,再调用 save、delete、find 等方法。

EntityManager 和 Repository 的方法

  • <font style="color:rgb(37, 41, 51);">save</font>:新增或者修改 Entity,如果传入了 id 会先 select 再决定修改还新增
  • <font style="color:rgb(37, 41, 51);">update</font>:直接修改 Entity,不会先 select
  • <font style="color:rgb(37, 41, 51);">insert</font>:直接插入 Entity
  • <font style="color:rgb(37, 41, 51);">delete</font>:删除 Entity,通过 id
  • <font style="color:rgb(37, 41, 51);">remove</font>:删除 Entity,通过对象
  • <font style="color:rgb(37, 41, 51);">find</font>:查找多条记录,可以指定 where、order by 等条件
  • <font style="color:rgb(37, 41, 51);">findBy</font>:查找多条记录,第二个参数直接指定 where 条件,更简便一点
  • <font style="color:rgb(37, 41, 51);">findAndCount</font>:查找多条记录,并返回总数量
  • <font style="color:rgb(37, 41, 51);">findByAndCount</font>:根据条件查找多条记录,并返回总数量
  • <font style="color:rgb(37, 41, 51);">findOne</font>:查找单条记录,可以指定 where、order by 等条件
  • <font style="color:rgb(37, 41, 51);">findOneBy</font>:查找单条记录,第二个参数直接指定 where 条件,更简便一点
  • <font style="color:rgb(37, 41, 51);">findOneOrFail</font>:查找失败会抛 EntityNotFoundError 的异常
  • <font style="color:rgb(37, 41, 51);">query</font>:直接执行 sql 语句
  • <font style="color:rgb(37, 41, 51);">createQueryBuilder</font>:创建复杂 sql 语句,比如 join 多个 Entity 的查询
  • <font style="color:rgb(37, 41, 51);">transaction</font>:包裹一层事务的 sql
  • <font style="color:rgb(37, 41, 51);">getRepository</font>:拿到对单个 Entity 操作的类,方法同 EntityManager

一对一的关系映射与 CRUD

CURD 即 创建(Create)、读取(Read)、更新(Update)和删除(Delete)

TypeORM 里一对一关系的映射通过 <font style="color:rgb(37, 41, 51);">@OneToOne</font> 装饰器来声明,维持外键列的 Entity 添加 <u><font style="color:rgb(37, 41, 51);">@JoinColumn</font></u> 装饰器。

可以通过 <font style="color:rgb(37, 41, 51);">@OneToOn</font> 装饰器的 onDeleteonUpdate 参数设置级联删除和更新的方式,比如 CASCADE、SET NULL 等。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
@Entity()
export class IdCard {
@PrimaryGeneratedColumn()
id: number;

@Column({ length: 50, comment: "身份证号码" })
cardName: string;

@JoinColumn()
@OneToOne(() => User, {
cascade: true,
onDelete: "CASCADE",
onUpdate: "CASCADE",
})
user: User;
}

如果是非外键列的 Entity,想要关联查询另一个 Entity,则需要通过第二个参数指定外键列是另一个 Entity 的哪个属性。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
@Entity()
export class User {
@PrimaryGeneratedColumn()
id: number;

@Column()
firstName: string;

@Column()
lastName: string;

@Column()
age: number;

@OneToOne(() => IdCard, (IdCard) => IdCard.user)
idCard: IdCard;
}

还可以设置 cascade,也就是 save 的时候会自动级联相关 Entity 的 save。

增删改分别通过 save 和 delete 方法,查询可以通过 find 也可以通过 queryBuilder,不过要 find 的时候要指定 relations 才会关联查询。

1
2
3
4
5
const users = await AppDataSource.manager.find(User, {
relations: {
idCard: true,
},
});

一对多的关系映射与 CRUD

一对多关系的映射,通过 <font style="color:rgb(37, 41, 51);">@ManyToOne</font> 或者 <font style="color:rgb(37, 41, 51);">@OneToMany</font> 装饰器。

TypeORM 会自动在<font style="color:rgb(37, 41, 51);">多</font>的那一方添加外键,不需要通过 @JoinColumn 指定,不过你可以通过 @JoinColumn 来修改外键列的名字。

双方只能有一方 <font style="color:rgb(37, 41, 51);">cascade</font>,不然会无限循环。设置了 <font style="color:rgb(37, 41, 51);">cascade</font> 之后,只要一方保存,关联的另一方就会自动保存。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
// 主表(一的那一方) 使用@OneToMany
@Entity()
export class Department {
@PrimaryGeneratedColumn()
id: number;

@Column({
length: 50,
})
name: string;

// 同样需要第二个参数指定外键列在 employee.department 中维护。
@OneToMany(() => Employee, (employee) => employee.department, {
cascade: true,
})
employees: Employee[];
}

// 从表(多的那一方) 使用@ManyToOne
@Entity()
export class Employee {
@PrimaryGeneratedColumn()
id: number;

@Column({
length: 50,
})
name: string;

@ManyToOne(() => Department)
department: Department;
}

删除的话,如果设置了外键的 CASCADE 或者 SET NULL,那只删除主表(一的那一方)对应的 Entity 就好了,msyql 会做后续的关联删除或者 id 置空。否则就要先删除所有的从表(多的那一方)对应的 Entity 再删除主表对应的 Entity。

多对多的关系映射与 CRUD

这多对多关系在 Entity 映射,是通过 <font style="color:rgb(37, 41, 51);">@ManyToMany</font><font style="color:rgb(37, 41, 51);">@JoinTable</font> 来声明的。<font style="color:rgb(37, 41, 51);">@ManyToMany</font>来声明这是一个多对多的关系。而<font style="color:rgb(37, 41, 51);">@JoinTable</font>将生成一个额外的表来管理其关系。

如果想从任何一个实体检索或修改关系。则双方都应该保留了对方的引用,需要<font style="color:rgb(37, 41, 51);">@ManyToMany</font>第二个参数来指定关联的外键列在哪,也就是如何查找当前 entity。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
@Entity()
export class Article {
@PrimaryGeneratedColumn()
id: number;

@Column({ length: 10, comment: "文章标题" })
title: string;

@Column({ type: "text", comment: "文章内容" })
content: string;

@ManyToMany(() => Tag, (tag) => tag.article)
@JoinTable()
tags: Tag[];
}

@Entity()
export class Tag {
@PrimaryGeneratedColumn()
id: number;

@Column({ length: 100 })
name: string;

@ManyToMany(() => Article, (article) => article.tags)
article: Article;
}

多对多关系的修改只要查出来之后修改下属性,然后 save,TypeORM 会自动去更新中间表。

<font style="color:rgb(37, 41, 51);">@JoinTable</font> 装饰器应在 <font style="color:rgb(37, 41, 51);">@ManyToMany</font> 之后,并且 <u><font style="color:rgb(37, 41, 51);">@JoinTable</font></u>只能在一个实体上声明,通常应该在持有“主动”的一方(即添加或删除关联操作更常见的一方)声明


本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!