Understanding Relationships in TypeORM
Tags: database, typescript, typeorm
Published: 2023-01-13 09:17:52

## What is TypeORM?
Understanding how relationships works in database management is a concept that is important as a software engineer.
In this article, we would learn what typeORM is, how relationships work in typeORM and the importance of relationships in database management.

If we are creating a typescript application and need a database for backend services, we will need an ORM (Object Relational Mapper) to connect our application to the database. 
**Object** denotes the model in your application, **Relational** denotes the relationship between tables in a Relational Database Management System(RDMS), and **Mapping** denotes the act of connecting the model and our tables.

TypeORM is a TypeScript ORM (object-relational mapper) library that simplifies the integration of your TypeScript application with a relational database. MySQL, SQLite, Postgres, MS SQL Server, and a variety of other relational databases are supported by this library.

## Relationships in TypeORM

In TypeORM, relationships exist between tables in the database. When one of the tables has a foreign key that references the primary key of the other table, a relationship exists. This feature enhances the power and efficiency with which relational databases store information.

TypeORM enables entities to be related to one another and, as a result, to database tables.

> 
Entities are building blocks of a database.

In TypeORM, an Entity is a class that defines a collection of fields or columns as well as database operations. It is made up of columns and relationships.


In general, relationships can be divided into four types.

1. One-to-one relationship
2. One-to-many relationship
3. Many-to-one relationship
4. Many-to-many relationship

## One-to-one relationship

When an instance of one table, say Table A, contains an instance of another table, say Table B, a one-to-one relationship is formed. For instance, we could use a user's post on a website. The requirement here is that a user can only make one post.

We'd need two tables here: User table and Post table. The **User** table will contain the user's information, and the **Post** table will contain the post information as well as the user information who made the post on the site.

To accomplish this, we'll need two entities: User entity and Post entity.

```
//User.entity.ts
import {Entity, PrimaryGeneratedColumn, Column} from "typeorm";

@Entity() 
export class User {
   @PrimaryGeneratedColumn() 
   id: number; 
   
   @Column() 
   name: string; 
}
```
**Result**
![One-to-one relationship](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9nrf6ox2rkwst8sbd4gk.png)

The User entity has an `id` column which is a primarily generated column with an auto-increment value that is automatically generated. It also has a `name` column that is string-based.
```
//Post.entity.ts
import {Entity, PrimaryGeneratedColumn, Column, OneToOne, JoinColumn} from "typeorm"; 
import {User} from "./User.entity"; 

@Entity() 
export class Post { 
   @PrimaryGeneratedColumn() 
   id: number; 
   
   @Column() 
   post: string; 
   
   @OneToOne(type => User) 
   @JoinColumn() 
   user: User;
}
```
**Result** 
![One-to-one relationship](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/wk9of0wsknlb9m78umka.png)

The Post entity has an `id` which is a primarily generated column and a string typed column called `post`. 
It has a third column that is joined to the User entity via the `@JoinColumn` decorator.
A one-to-one relationship with the type directed to the User entity is established in this column.

`@JoinColumn` specifies which side of the relation contains the join column with a foreign key. It allows you to customise the names of the join column and the referenced column.

When we use `@JoinColumn` on a column, the database creates a column by default named _propertyName + referencedColumnName_. In the example used above, the property name is **user** while the referenced column name is by default **id** of the User entity, therefore a new column called `userId` is created as shown in the result above.

However, the column name can be explicitly set instead of the default naming convention by using
 `@JoinColumn({  name: "user_post_id" })`

```
//Post.entity.ts 
import {
  Entity,
  PrimaryGeneratedColumn,
  Column,
  OneToOne,
  JoinColumn,
} from 'typeorm';
import { User } from './User.entity';

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

  @Column()
  post: string;

  @OneToOne((type) => User)
  @JoinColumn({  name: "user_post_id" })
  user: User;
}

```
In the code snippet above, the `@JoinColumn` had a name property added, therefore the new column created will be `user_post_id`instead of the default name of `userId`.

**Result** 
![@JoinColumn](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ify17wfk6ry7o1k684zn.png)

> The `@JoinColumn` always refers to the primary column of the related entity by default.

If we want to create a relationship with other columns of the related entity, we can do so as:
```
//User.entity.ts 
import { Entity, PrimaryColumn, Column } from 'typeorm';

@Entity()
export class User {
  @Column()
  id: number;

  @PrimaryColumn()
  name: string;
}
```
This entity is quite different from the one created above in that the `name` is the primary column and not the `id` column. This is necessary because we intend to reference `name` column in the `JoinColumn` for Post entity below and it has been earlier stated that the `@JoinColumn` can only reference a primary column. 
```
//Post.entity.ts 
import {
  Entity,
  PrimaryGeneratedColumn,
  Column,
  OneToOne,
  JoinColumn,
} from 'typeorm';
import { User } from './User.entity;

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

  @Column()
  post: string;

  @OneToOne((type) => User)
  @JoinColumn({ referencedColumnName: 'name' })
  user: User;
}

```
**Result** 
![@JoinColumn](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ergmcib94juulpkxs8kk.png)

## One-to-many relationship

When one row in one table, say Table A, is linked to multiple rows in another table, say Table B, but only one row in Table B is linked to one row in Table A, a one-to-many relationship is formed.

In the case of a Customer and an account entity, a customer can own multiple accounts, whereas an account can only be owned by one customer.
```
//Customer.entity.ts
import { Entity, PrimaryGeneratedColumn, Column, OneToMany } from 'typeorm';
import { Account } from './Account.entity;

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

  @Column()
  name: string;

  @OneToMany(() => Account, (account) => account.customer)
  account: Account[];
}

```
**Result** 
![One-to-many relationship](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9uyd5ou5yx6mjhjf2k87.png)

The Customer entity has a name column and has a one-to-many relationship because one customer can have many account. We added `@OneToMany` to the account property in the customer entity and specified Account as the target relation type.

> It is important to note that the `@JoinColumn` can be omitted in a many-to-one or one-to-many relationship.

```
//Account.entity.ts
import { Entity, PrimaryGeneratedColumn, ManyToOne } from 'typeorm';
import { Customer } from './Customer.model';

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

  @ManyToOne(() => Customer, (customer) => customer.account)
  customer: string;
}

```
**Result** 
![One-to-many relationship](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/0adi882302tipegh7hi8.png)
The Account entity has a many-to-one relationship because multiple accounts could belong to one customer.
We added `@ManyToOne` to the customer property in the Account entity and specified Customer as the target relation type.

> `@ManyToOne` cannot exist without `@OneToMany`as it is required if `@OneToMany`needs to be used.

## Many-to-one relationship

This relationship is similar to a one-to-many relationship but from a different perspective.

When multiple rows in one table are linked to a single row in another table, a many-to-one relationship is formed.

Looking at a Customer and an Account entity, where a customer can own many accounts in a one-to-many relationship, it is also true that multiple accounts can belong to a single customer in a many-to-one relationship.

Multiple entries in the account table can belong to the same row in the customer table.
An example is quite similar to the one-to-many relationship explained above.

## Many-to-many relationship

When multiple rows in one table are linked to multiple rows in another table, a many-to-many relationship is formed.

In a Customer and Product entity, for example, a customer can buy more than one product, and a product can be bought by more than one customer.
```
//Product.entity.ts 
import { Entity, PrimaryGeneratedColumn, Column } from "typeorm"

@Entity()
export class Product {
    @PrimaryGeneratedColumn()
    id: number

    @Column()
    name: string
}
```
**Result** 
![Many-to-many relationship](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/nihrmqr0vjkv37hiibdl.png)
```
//Customer.entity.ts 
import {
    Entity,
    PrimaryGeneratedColumn,
    Column,
    ManyToMany,
    JoinTable,
} from "typeorm"
import { Product } from "./Product.entity"

@Entity()
export class Customer {
    @PrimaryGeneratedColumn()
    id: number

    @Column()
    name: string

    @ManyToMany(() => Product)
    @JoinTable()
    product: Product[]
}
```
The Customer and the Product entity are quite similar except the Many-to-many relationship built on the product column of the Customer table. This table is joined with the Product table using a `@JoinTable` decorator. 

> `@JoinTable` should be added to one of the entities, typically the owning entity.

Due to this decorator, a new table will be created with the default name as _table_tableProperty_referencedTable_. 
In our example, this table will be created as `customer_product_product`. In this new table, there are two columns which are `customerId` and `productId`. 
Data stored in this table are entries of a customer id and multiple products bought by such customer and also entries of product id and customers who bought them.
**Result** 
![Many-to-many relationship](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/pzlswttvhknj9vl24ecf.png)

## Why is this knowledge important?
Understanding how relationships work in database management is an important concept for a software engineer to understand. The significance of this knowledge cannot be overstated, as relationships are the logic that underpins business rules. Databases are generally about table interaction, and by understanding how the interaction/relationships work, you can begin to make more meaningful business designs as a developer. It aids in the avoidance of many schema errors in database design, as well as the reduction of future limitations in the enhancement of business features.

## Conclusion
In this article, we learned how relationships work and the different types of database relationships in typeORM. We also briefly discussed why understanding relationships is important in database management.