Entities act as the glue between business logic and the database representation of the application data. As a result, they act as the foundation of any ORM. The same goes with TypeORM Entities.

An Entity in TypeORM is a class that defines a collection of fields or columns along with database operations. A TypeORM Entity maps to an equivalent table in the database. In other words, the structure of the application database directly depends on the entities defined using TypeORM syntax. TypeORM provides several decorators that help us design effective entities for various requirements.

In this post, we will learn about TypeORM Entities with example.

1 – How do I create a TypeORM Entity?

In TypeORM, we can declare a class as an Entity by using the @Entity() annotation. Also, every field is annotated with @Column() annotation.

See below example:

@Entity()
export class Flight {

    @PrimaryGeneratedColumn()
    id: number;

    @Column()
    source: string;

    @Column()
    destination: string;
}

Based on the definition in the Entity class, TypeORM will create the corresponding table in the database. To inform TypeORM about our entities, we need to add the entity in the DataSource object as below.

import "reflect-metadata"
import { DataSource } from "typeorm"
import { Flight } from "./entity/Flight"

export const AppDataSource = new DataSource({
    type: "postgres",
    host: "localhost",
    port: 5432,
    username: "postgres",
    password: "password",
    database: "flight-booking",
    synchronize: true,
    dropSchema: true,
    logging: false,
    entities: [Flight],
    migrations: [],
    subscribers: [],
})

If interested, you can refer to our detailed post on configuring a TypeORM DataSource object.

2 – TypeORM Entities Example

Let us create a bigger Entity definition. We will extend the example of storing flight-related information.

See below the entity class for the same:

import { BaseEntity, BeforeInsert, Column, CreateDateColumn, Entity, PrimaryGeneratedColumn, UpdateDateColumn } from "typeorm";

export enum FlightType {
    DOMESTIC = "domestic",
    INTERNATIONAL = "international",
}

@Entity()
export class Flight {

    @PrimaryGeneratedColumn()
    id: number;

    @Column()
    source: string;

    @Column()
    destination: string;

    @Column({
        generatedType: 'STORED',
        asExpression: `source || destination`
    })
    sourceDestinationCode: string;

    @Column()
    category: string;

    @Column()
    flightCode: string;

    @Column({
        type: "enum",
        enum: FlightType,
        default: FlightType.DOMESTIC
    })
    flightType: FlightType;

    @Column({type: "float"})
    durationInHours: number;

    @Column()
    availableSeats: number;

    @CreateDateColumn()
    createdDate: Date;

    @UpdateDateColumn()
    lastUpdatedDate: Date;

    @BeforeInsert()
    updateFlightCode() {
        const randomFlightNumber = Math.floor(Math.random() * 1000);

        this.flightCode = this.category.concat(randomFlightNumber.toString());
    }
}

Let us look at the various field types in more detail:

2.1 – TypeORM Primary Columns

Every TypeORM Entity must have at least one primary column.

@PrimaryGeneratedColumn()
id: number;

We can use @PrimaryGeneratedColumn() decorator to define a primary column. Basically, TypeORM will automatically generate the value for such a column.

There are other variations to the primary column.

  • The @PrimaryColumn() decorator declares a column as primary. However, it does not automatically generate the value for such a column. We have to manually assign the value for such a column.
  • The @PrimaryGeneratedColumn(“uuid”) column creates a primary column with uuid values. Basically, TypeORM will assign the value to this column.
  • Also, we can have composite primary columns. Basically, this is a combination of columns forming a primary column.
@PrimaryColumn()
source: string;

@PrimaryColumn()
destination: string;

2.2 – Normal TypeORM Columns

Normal columns in TypeORM Entities are defined using @Column() decorator.

See below example:

@Column()
source: string;

@Column()
destination: string;

In case we want to define columns with float type, we can provide an additional configuration to the @Column() decorator.

@Column({type: "float"})
durationInHours: number;

2.3 – TypeORM Enum Column

TypeORM also supports Enum columns. However, this support is applicable only for postgresql and mysql databases.

See below example of a TypeORM Enum Column.

export enum FlightType {
    DOMESTIC = "domestic",
    INTERNATIONAL = "international",
}

@Entity()
export class Flight {

    @PrimaryGeneratedColumn()
    id: number;

    @Column()
    source: string;

    @Column()
    destination: string;

    @Column({
        type: "enum",
        enum: FlightType,
        default: FlightType.DOMESTIC
    })
    flightType: FlightType;
}

Basically, we declare an enum FlightType with two possible values. Then, we can use the FlightType enum within the @Column() decorator.

As you can see, the @Column() decorator takes a configuration object. Basically, in this object, we can declare the type of field and also the associated enum. Also, we can provide a default value.

2.4 – TypeORM Generated Column

TypeORM also provides an option of Generated column. Basically, this column is extremely useful when we want to generate the value for a particular field based on some other fields.

See below example:

@Column({
    generatedType: 'STORED',
    asExpression: `source || destination`
})
sourceDestinationCode: string;

Basically, we provide an expression as part of the @Column() decorator. The value will be a concatenation of the source and destination fields. The generatedType STORED means that we want to actually store the value in the database. TypeORM also supports VIRTUAL fields where the value is not stored in the database.

2.5 – TypeORM Before Insert Example

TypeORM also provides Entity Listeners. By using them, we can generate values for certain columns based on database events such as before insert, after insert and so on.

See below TypeORM Before Insert example.

@Column()
flightCode: string;

@BeforeInsert()
updateFlightCode() {
    const randomFlightNumber = Math.floor(Math.random() * 1000);

    this.flightCode = this.category.concat(randomFlightNumber.toString());
}

This is a great place to place logic for computing values. In the above example, we generate a random number using Math function and use it to update the value of flightCode before inserting in the database.

2.6 – TypeORM Timestamp Columns

TypeORM also provides decorators to handle create and update timestamp columns without writing external logic.

See below example:

@CreateDateColumn()
createdDate: Date;

@UpdateDateColumn()
lastUpdatedDate: Date;

Basically, we use @CreateDateColumn() and @UpdateDateColumn() decorators. This will ensure that while creating or updating records, TypeORM will update the values of these fields.

3 – Using TypeORM Entities

Now that we have defined the TypeORM Entity and understood the various types of columns, we can use the entity within the application.

See below example on how to actually work with the entity.

import { AppDataSource } from "./data-source"
import { Flight } from "./entity/Flight"

AppDataSource.initialize().then(async () => {

    console.log("Inserting a new flight into the database...")

    const flight = new Flight()

    flight.source = "LAX";
    flight.destination = "NYC";
    flight.category = "7G";
    flight.durationInHours = 4.5;
    flight.availableSeats = 150;

    const flightRepository = AppDataSource.getRepository(Flight);

    await flightRepository.save(flight);

    console.log("Saved a new flight with id: " + flight.id)

    console.log("Loading flights from the database...")
    const flights = await flightRepository.find()
    console.log("Loaded flights: ", flights)

}).catch(error => console.log(error))

As you can see, we create a Flight object and then assign values to several fields. After saving the Flight record, we fetch it again using flightRepository.find() method.

Below is the output of the console statements:

Inserting a new flight into the database...
Saved a new flight with id: 1
Loading flights from the database...
Loaded flights:  [
  Flight {
    id: 1,
    source: 'LAX',
    destination: 'NYC',
    sourceDestinationCode: 'LAXNYC',
    category: '7G',
    flightCode: '7G538',
    flightType: 'domestic',
    durationInHours: 4.5,
    availableSeats: 150,
    createdDate: 2022-03-31T02:24:39.380Z,
    lastUpdatedDate: 2022-03-31T02:24:39.380Z
  }
]

Though we assigned only a few fields with values, the complete Flight object was created and inserted into the flight table.

For your information, here we used the TypeORM Data Mapper pattern with dedicated repositories. However, TypeORM also supports the Active Record pattern. If interested, you can read our detailed post about TypeORM Active Record vs Data Mapper.

Conclusion

TypeORM Entities are quite intuitive and easy to use. However, they also provide various options for customization. We looked at few of the important aspects in this post.

Want to see TypeORM in action for a real project? Check out this post on NestJS TypeORM Integration.

Going further, you can also learn about TypeORM Entity Inheritance to avoid duplication in your entity definitions.

If you have any comments or queries about this post, please feel free to mention them in the comments section below.

Categories: BlogTypeORM

Saurabh Dashora

Saurabh is a Software Architect with over 12 years of experience. He has worked on large-scale distributed systems across various domains and organizations. He is also a passionate Technical Writer and loves sharing knowledge in the community.

1 Comment

Anonymous · March 14, 2023 at 7:22 am

good

Leave a Reply

Your email address will not be published. Required fields are marked *