TypeORM - 关系


关系用于指数据库中表之间的关系。通常,当两个表之一具有引用另一个表的主键的外键时,两个表之间就存在关系。这一特性使得关系数据库更加强大并且能够高效地存储信息。

TypeORM 允许实体相互关联以及随后的数据库表。一般来说,关系可以分为四个更广泛的类别。它们如下:

一对一- 给定实体的一个对象仅与目标实体的一个对象相关,反之亦然。例如,一个国家只有一个首都,同样,一座城市也只能是一个国家的首都。

多对一- 给定实体的多个对象与目标实体的一个对象相关。例如,城市仅属于一个国家,但国家可以有多个城市。

一对多- 与多对一相同,只是关系相反。

多对多- 给定实体的多个对象与目标实体的多个对象相关。例如,一篇文章可能被标记在多个主题下,如编程语言、金融等,同时一个特定标签也可能有多篇文章。

TypeORM 还提供了增强实体关系的选项。它们如下 -

  • eager - 源实体对象也加载目标实体对象。
  • cascade - 在插入或更新源实体对象时插入或更新目标实体对象。
  • onDelete - 删除源实体对象时,目标实体对象也会被删除。
  • Primary - 用于指定关系列是否为主键。
  • nullable - 用于指定关系列是否可为空。

让我们详细了解不同类型的关系映射。

一对一

正如我们之前了解到的,一个表字段的实例包含另一个表字段的实例,反之亦然。让我们创建一个详细信息表 -

详情.ts

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

@Entity() 
export class Details {
   @PrimaryGeneratedColumn() 
   id: number; 
   
   @Column() 
   gender: string; 
   
   @Column() 
   country: string; 
}

让我们创建另一个实体 Customer,如下所示 -

客户.ts

import {Entity, PrimaryGeneratedColumn, Column, OneToOne, JoinColumn} from "typeorm"; 

import {Details} from "./Details"; 

@Entity() 
export class Customer { 

   @PrimaryGeneratedColumn() 
   id: number; 
   
   @Column() 
   name: string; 
   
   @OneToOne(type => Details) @JoinColumn() 
   details: Details;
}

这里,

我们添加了OneToOne详细信息表的映射。@JoinColumn()包含“关系 id”和客户表的外键。我们可以将关系保存在index.ts中,如下所示 -

const details = new Details(); details.gender = "female"; details.country = "india" await connection.manager.save(details);

const customer = new Customer(); customer.name = 'customer1'; customer.details = Details; await connection.manager.save(Customer);

一对多和多对一

正如我们之前了解到的,第一个表字段的实例包含第二个表字段的多个实例,称为一对多映射,第一个表的多个实例仅包含第二个表的一个实例,称为多对一映射。

考虑一个学生项目实体的示例,学生可以从事多个项目,但每个项目仅由一名学生处理。

让我们创建一个项目实体,如下所示 -

项目

import {Entity, PrimaryGeneratedColumn, Column, ManyToOne} from "typeorm"; import {Student} from "./Student"; 
@Entity() 
export class Project {  

   @PrimaryGeneratedColumn() 
   id: number; 
   
   @Column() 
   projects: string; 
   
   @ManyToOne(type => Student, student => student.projects) student: Student; 
}

现在,我们创建学生实体如下 -

import {Entity, PrimaryGeneratedColumn, Column, OneToMany} from "typeorm"; import {Project} from "./Project"; 

@Entity() 
export class User {  
   
   @PrimaryGeneratedColumn() 
   id: number; 
   
   @Column() 
   name: string; 
   
   @OneToMany(type => Project, project => project.student) projects: Project[];  
}

这里,

@OneToMany属性映射到Project@ManyToOne属性映射到Student。但是,如果没有@ManyToOne,@OneToMany就不能存在,并且@ManyToOne属性包含“关系id”和外键。

我们可以将连接保存在index.ts中,如下所示 -

const proj1 = new Project(); proj1.projects = "database management"; await connection.manager.save(proj1); 

const proj2 = new Project(); proj2.projects = "web application"; await connection.manager.save(proj2); 

const stud = new Student(); stud.name = "Student1"; stud.projects = [proj1, proj2]; await connection.manager.save(stud);

多对多

正如我们之前了解到的,它是通过一个表中的多个记录与另一个表中的多个记录相关来引用的。举个例子,大学生可以一次注册多个班级,这意味着学生每学期可能有四到五个班级,一个班级可以有很多学生。

我们可以简单的得出结论,一个学生有很多个班级,一个班级有很多个学生。让我们为创建一个实体,如下所示 -

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

@Entity() 
export class Classes { 

   @PrimaryGeneratedColumn() 
   id: number; 
   
   @Column() 
   name: string; 
}

现在,我们创建学生实体如下 -

import {Entity, PrimaryGeneratedColumn, Column, ManyToMany, JoinTable} from "typeorm"; 
import {Classes} from "./Classes";

@Entity() 
export class Student { 

   @PrimaryGeneratedColumn() 
   id: number; 
   
   @Column() 
   name: string;

   @Column() 
   subjects: string; 
   
   @ManyToMany(type => Classes) @JoinTable() 
   classes: Classes[];
}