Relations

What are relations

Relations helps you to work with related entities easily.There are several types of relations:

Relation options

There are several options you can specify for relations:

  • eager: boolean - If set to true, the relation will always be loaded with the main entity when using find* methods or QueryBuilder on this entity
  • cascade: boolean - If set to true, the related object will be inserted and update in the database.
  • onDelete: "RESTRICT"|"CASCADE"|"SET NULL" - specifies how foreign key should behave when referenced object is deleted
  • primary: boolean - Indicates whether this relation’s column will be a primary column or not.
  • nullable: boolean - Indicates whether this relation’s column is nullable or not. By default it is nullable.

Cascades

Cascades example:

  1. import {Entity, PrimaryGeneratedColumn, Column, ManyToMany} from "typeorm";
  2. import {Question} from "./Question";
  3. @Entity()
  4. export class Category {
  5. @PrimaryGeneratedColumn()
  6. id: number;
  7. @Column()
  8. name: string;
  9. @ManyToMany(type => Question, question => question.categories)
  10. questions: Question[];
  11. }
  1. import {Entity, PrimaryGeneratedColumn, Column, ManyToMany, JoinTable} from "typeorm";
  2. import {Category} from "./Category";
  3. @Entity()
  4. export class Question {
  5. @PrimaryGeneratedColumn()
  6. id: number;
  7. @Column()
  8. title: string;
  9. @Column()
  10. text: string;
  11. @ManyToMany(type => Category, category => category.questions, {
  12. cascade: true
  13. })
  14. @JoinTable()
  15. categories: Category[];
  16. }
  1. const category1 = new Category();
  2. category1.name = "animals";
  3. const category2 = new Category();
  4. category2.name = "zoo";
  5. const question = new Question();
  6. question.categories = [category1, category2];
  7. await connection.manager.save(question);

As you can see in this example we did not call save for category1 and category2.They will be automatically inserted, because we set cascade to true.

Keep in mind - great power comes with great responsibility.Cascades may seem like a good and easy way to work with relations,but they may also bring bugs and security issues when some undesired object is being saved into the database.Also, they provide a less explicit way of saving new objects into the database.

@JoinColumn options

@JoinColumn not only defines which side of the relation contains the join column with a foreign key,but also allows you to customize join column name and referenced column name.

When we set @JoinColumn, it automatically creates a column in the database named propertyName + referencedColumnName.For example:

  1. @ManyToOne(type => Category)
  2. @JoinColumn() // this decorator is optional for @ManyToOne, but required for @OneToOne
  3. category: Category;

This code will create a categoryId column in the database.If you want to change this name in the database you can specify a custom join column name:

  1. @ManyToOne(type => Category)
  2. @JoinColumn({ name: "cat_id" })
  3. category: Category;

Join columns are always a reference to some other columns (using a foreign key).By default your relation always refers to the primary column of the related entity.If you want to create relation with other columns of the related entity -you can specify them in @JoinColumn as well:

  1. @ManyToOne(type => Category)
  2. @JoinColumn({ referencedColumnName: "name" })
  3. category: Category;

The relation now refers to name of the Category entity, instead of id.Column name for that relation will become categoryName

@JoinTable options

@JoinTable is used for many-to-many relations and describes join columns of the “junction” table.A junction table is a special separate table created automatically by TypeORM with columns that refer to the related entities.You can change column names inside junction tables and their referenced columns with @JoinColumn:You can also change the name of the generated “junction” table.

  1. @ManyToMany(type => Category)
  2. @JoinTable({
  3. name: "question_categories", // table name for the junction table of this relation
  4. joinColumn: {
  5. name: "question",
  6. referencedColumnName: "id"
  7. },
  8. inverseJoinColumn: {
  9. name: "category",
  10. referencedColumnName: "id"
  11. }
  12. })
  13. categories: Category[];

If the destination table has composite primary keys,then an array of properties must be sent to @JoinTable.