TypeOrm Relationships and Foreign Keys

📘TypeORM Relationships & Foreign Keys

🔑What is a Foreign Key?

A foreign key (FK) is a column in one table that references the primary key (PK) in another table.

  • Creates a relationship between two tables
  • Ensures referential integrity: you cannot point to something that doesn't exist

💡Real-Life Analogy

A post has an author ID field. That ID is the foreign key linking the post to the user who wrote it.


⚖️One-to-One (@OneToOne)

Example: User has one Profile, Profile belongs to one User

@Entity() export class User { @PrimaryGeneratedColumn() id: number; @OneToOne(() => Profile, profile => profile.user) @JoinColumn() // This side has the foreign key! profile: Profile; } @Entity() export class Profile { @PrimaryGeneratedColumn() id: number; @OneToOne(() => User, user => user.profile) user: User; }

🧠Notes

  • Foreign key goes on one side only — the side with @JoinColumn() is the owning side
  • Creates: user.profileId in the User table (or whichever side you put @JoinColumn on)

⚖️One-to-Many / Many-to-One

Example: User has many Posts, Each Post belongs to one User

@Entity() export class User { @PrimaryGeneratedColumn() id: number; @OneToMany(() => Post, post => post.user) posts: Post[]; } @Entity() export class Post { @PrimaryGeneratedColumn() id: number; @ManyToOne(() => User, user => user.posts) user: User; // This side has the foreign key! }

🧠Notes

  • The @ManyToOne side is always the owning side
  • Creates: post.userId in the Post table

💡Analogy

A User writes many Posts. Each Post stores the ID of its author as a foreign key.


⚖️Many-to-Many (@ManyToMany)

Example: Students can join many Courses, Courses can have many Students

@Entity() export class Student { @PrimaryGeneratedColumn() id: number; @ManyToMany(() => Course, course => course.students) @JoinTable() // This side owns the relationship! courses: Course[]; } @Entity() export class Course { @PrimaryGeneratedColumn() id: number; @ManyToMany(() => Student, student => student.courses) students: Student[]; }

🧠Notes

  • Neither table gets a foreign key directly
  • Instead, a join table is created automatically: student_courses
  • With studentId (FK) and courseId (FK) columns
  • The side with @JoinTable() is the owning side

💡Analogy

Students and Courses have a many-to-many relationship. A middle table records who joined which course.


🔁Self-Referencing Relationship

Example: A User can have a manager (who is also a User), A User can manage many other Users

@Entity() export class User { @PrimaryGeneratedColumn() id: number; @Column() name: string; // Each user may have one manager @ManyToOne(() => User, user => user.subordinates) manager: User; // This side has the foreign key! // Each user may manage many subordinates @OneToMany(() => User, user => user.manager) subordinates: User[]; }

🧠Notes

  • This is a self-join: both sides are the same entity
  • The manager field is a foreign key referencing the same table (user.id)
  • The @ManyToOne side is again the owning side, holding the foreign key

💡Real-Life Analogy

An employee reports to one manager, and a manager can have many employees under them.

📊Table Structure Example

id name managerId (FK)
1 Alice NULL
2 Bob 1
3 Carol 1
  • Alice is the manager of Bob and Carol
  • Bob.managerId = 1 (points to Alice)

📌Quick Ownership Summary

Relationship Type Owning Side Where FK is stored
@OneToOne Side with @JoinColumn() In that entity's table
@OneToMany / @ManyToOne @ManyToOne side In the Many side table
@ManyToMany Side with @JoinTable() In a separate join table
Self-Referencing @ManyToOne side In the same table (self FK)

Key Points to Remember

  • Only the owning side writes the foreign key to the database
  • The inverse side is just for navigation and does not hold any column
  • Relationships let you navigate objects in TypeORM while the database stores foreign keys behind the scenes

💡Pro Tip: Always remember which side owns the relationship - it determines where your foreign keys are stored in the database!

Comments

Popular Posts