Database Integration with TypeORM
Connecting to a database (e.g., PostgreSQL, MySQL) using TypeORM. Defining entities, repositories, and performing CRUD operations.
Defining Entities with TypeORM in NestJS
TypeORM is a powerful ORM (Object-Relational Mapper) that allows you to interact with databases using TypeScript. In a NestJS application, TypeORM provides a clean and efficient way to define your database schema as entities, which are essentially classes that map to database tables. This guide explains how to define these entities, their columns, data types, and relationships.
Creating Entity Classes
Entities represent the structure of your database tables. You create them as TypeScript classes and use TypeORM decorators to define how they map to the database.
Here's a basic example of an entity representing a `User` table:
import { Entity, PrimaryGeneratedColumn, Column } from 'typeorm';
@Entity() // This decorator marks the class as a TypeORM entity
export class User {
@PrimaryGeneratedColumn() // This column is the primary key and will be auto-generated
id: number;
@Column({ length: 100 }) // This column represents the username with a maximum length of 100 characters
username: string;
@Column({ unique: true }) // This column represents the email and must be unique
email: string;
@Column({ nullable: true }) // This column represents the age and is allowed to be null
age: number;
}
Explanation:
@Entity()
: This decorator marks theUser
class as a TypeORM entity. This tells TypeORM that this class represents a table in your database. By default, the table name will be the same as the class name (user
in this example, TypeORM automatically lowercases and pluralizes by default unless configured otherwise). You can specify a custom table name using@Entity('users')
.@PrimaryGeneratedColumn()
: This decorator designates theid
property as the primary key column. ThePrimaryGeneratedColumn
decorator automatically generates a unique value for each new record.@Column()
: This decorator defines a column in the table. You can specify various options within the decorator, such as:length
: Sets the maximum length of a string column.unique
: Enforces uniqueness for the column's values.nullable
: Indicates whether the column can containnull
values. Defaults tofalse
.type
: Specifies the data type of the column (e.g.,'varchar'
,'int'
,'text'
,'boolean'
,'date'
,'json'
). If not specified, TypeORM will attempt to infer the type from the TypeScript property type.default
: Sets a default value for the column if no value is provided during insertion.
Data Types
TypeORM supports various data types. Here are some common examples:
string
: Maps toVARCHAR
orTEXT
depending on thelength
option.number
: Maps toINT
,BIGINT
,FLOAT
, orDOUBLE
depending on the precision and scale.boolean
: Maps toBOOLEAN
orTINYINT(1)
.Date
: Maps toDATE
,DATETIME
, orTIMESTAMP
.JSON
: Maps toJSON
orTEXT
depending on the database.
Defining Relationships
TypeORM simplifies defining relationships between entities. Common relationships include:
- One-to-One: One entity is related to exactly one other entity.
- One-to-Many: One entity is related to multiple entities.
- Many-to-One: Multiple entities are related to one entity (the inverse of One-to-Many).
- Many-to-Many: Multiple entities are related to multiple other entities.
Let's illustrate a One-to-Many relationship between a `User` and a `Post` entity:
// post.entity.ts
import { Entity, PrimaryGeneratedColumn, Column, ManyToOne, JoinColumn } from 'typeorm';
import { User } from './user.entity'; // Assuming user.entity.ts exists
@Entity()
export class Post {
@PrimaryGeneratedColumn()
id: number;
@Column()
title: string;
@Column()
content: string;
@ManyToOne(() => User, (user) => user.posts) // Defines the Many-to-One relationship to User
@JoinColumn({ name: 'userId' }) // Defines the foreign key column name in the Post table
user: User;
}
// user.entity.ts
import { Entity, PrimaryGeneratedColumn, Column, OneToMany } from 'typeorm';
import { Post } from './post.entity';
@Entity()
export class User {
@PrimaryGeneratedColumn()
id: number;
@Column()
username: string;
@OneToMany(() => Post, (post) => post.user) // Defines the One-to-Many relationship to Post
posts: Post[];
}
Explanation:
@ManyToOne(() => User, (user) => user.posts)
: In thePost
entity, this decorator defines a Many-to-One relationship with theUser
entity. The first argument,() => User
, specifies the target entity. The second argument,(user) => user.posts
, is a function that points to the property in theUser
entity that represents the inverse side of the relationship (posts
). This is crucial for TypeORM to manage the relationship correctly.@JoinColumn({ name: 'userId' })
: This decorator, also in thePost
entity, specifies the foreign key column name in thePost
table that will store theUser
's ID. Without@JoinColumn
, TypeORM would create a default column name (e.g., `userId`). Specifying the name explicitly is generally good practice for clarity and control.@OneToMany(() => Post, (post) => post.user)
: In theUser
entity, this decorator defines a One-to-Many relationship with thePost
entity. The first argument,() => Post
, specifies the target entity. The second argument,(post) => post.user
, points to the property in thePost
entity (user
) that represents the inverse side of the relationship.posts: Post[]
: This property in theUser
entity is an array ofPost
objects. TypeORM will automatically populate this array when you fetch aUser
and request its related posts.
By defining entities and relationships in this way, TypeORM allows you to work with your database in an object-oriented manner, making your code more readable, maintainable, and easier to test within your NestJS application.