TypeORM - Relations


Advertisements

Relations are used to refer the relationship between table in database. In general, a relationship exists between two tables when one of them has a foreign key that references the primary key of the other table. This feature makes relational database more powerful and efficiently store information.

TypeORM allows the entities to be related to each other and subsequently database tables. In general, relationship can be classified into four broader categories. They are as follows,

one-to-one − One object of the given entity relates to only one object of the target entity and vice versa. For example, a country will have only one capital city and similarly a city will be capital of only one country.

many-to-one − Multiple object of the given entity relates to one object of the target entity. For example, city comes under only one country but country can have multiple cities.

one-to-many − Same as many-to-one except the relationship is reversed.

many-to-many − Multiple object of the given entity relates to multiple object of the target entity. For example, an article may be tagged under multiple topic like programming language, finance, etc., and at the same time a particular tag may have multiple articles as well.

TypeORM also provides options to enhance the relationship of the entities. They are as follows −

  • eager − Source entity object loads the target entity objects as well.
  • cascade − Target entity object gets inserted or updated while the source entity object is inserted or updated.
  • onDelete − Target entity objects get deleted as well while the source entity object is deleted.
  • primary − Used to specify that the relation column is primary key or not.
  • nullable − Used to specify that the relation column is nullable or not.

Let us go through different types of relation mapping in detail.

One-to-One

As we learned earlier, it is referred by the instance of one table field contains the instance of another table field and vice versa. Let us create a Details table −

Details.ts

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

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

Let’s create an another entity Customer as follows −

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;
}

Here,

We have added mapping OneToOne to Details table. @JoinColumn() contain a “relation id” and foreign key to Customer table. We can save the relation in index.ts as follows −

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);

One-to-Many and Many-to-One

As we learned earlier, it is referred by the instance of first table field contains the multiple instances of second table field called One-to-Many mapping and multiple instances of first table contains only one instance of second table called Many-to-One mapping.

Consider an example of Student and project entities whereas, student can work on more than one project but each project is handled by only one student.

Let’s create a Project entity as follows −

Project

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; 
}

Now, we create Student entity as below −

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[];  
}

Here,

@OneToMany property mapped Project and @ManyToOne property mapped to Student. However, @OneToMany cannot exist without @ManyToOne and @ManyToOne property contain “relation id” and foreign key.

We can save the connection in index.ts as follows −

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);

Many-to-Many

As we learned earlier, it is referred by multiple records in one table are related to multiple records in another table. Consider an example, University student can be enrolled in multiple classes at a time which means student may have four or five classes per semester and a class can have many students.

We can simply conclude, a student has many classes, and a class has many students. Let’s create an entity for Classes as follows −

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

@Entity() 
export class Classes { 

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

Now, we create Student entity as below −

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[];
}
Advertisements