Relations Many-to-one and One-to-Many Many-to-one / one-to-many relations
Many-to-one / one-to-many is a relation where A contains multiple instances of B, but B contains only one instance of A. Let's take for example User
and Photo
entities. User can have multiple photos, but each photo is owned by only one single user.
Copy import {Entity , PrimaryGeneratedColumn , Column , ManyToOne} from "typeorm" ;
import {User} from "./User" ;
@ Entity ()
export class Photo {
@ PrimaryGeneratedColumn ()
id : number ;
@ Column ()
url : string ;
@ ManyToOne (() => User , user => user .photos)
user : User ;
}
Copy import {Entity , PrimaryGeneratedColumn , Column , OneToMany} from "typeorm" ;
import {Photo} from "./Photo" ;
@ Entity ()
export class User {
@ PrimaryGeneratedColumn ()
id : number ;
@ Column ()
name : string ;
@ OneToMany (() => Photo , photo => photo .user)
photos : Photo [];
}
Here we added @OneToMany
to the photos
property and specified the target relation type to be Photo
. You can omit @JoinColumn
in a @ManyToOne
/ @OneToMany
relation. @OneToMany
cannot exist without @ManyToOne
. If you want to use @OneToMany
, @ManyToOne
is required. However, the inverse is not required: If you only care about the @ManyToOne
relationship, you can define it without having @OneToMany
on the related entity. Where you set @ManyToOne
- its related entity will have "relation id" and foreign key.
This example will produce following tables:
Copy +-------------+--------------+----------------------------+
| photo |
+-------------+--------------+----------------------------+
| id | int(11) | PRIMARY KEY AUTO_INCREMENT |
| url | varchar(255) | |
| userId | int(11) | FOREIGN KEY |
+-------------+--------------+----------------------------+
+-------------+--------------+----------------------------+
| user |
+-------------+--------------+----------------------------+
| id | int(11) | PRIMARY KEY AUTO_INCREMENT |
| name | varchar(255) | |
+-------------+--------------+----------------------------+
Example how to save such relation:
Copy const photo1 = new Photo();
photo1.url = "me.jpg";
await connection.manager.save(photo1);
const photo2 = new Photo();
photo2.url = "me-and-bears.jpg";
await connection.manager.save(photo2);
const user = new User();
user.name = "John";
user.photos = [photo1, photo2];
await connection.manager.save(user);
or alternative you can do:
Copy const user = new User();
user.name = "Leo";
await connection.manager.save(user);
const photo1 = new Photo();
photo1.url = "me.jpg";
photo1.user = user;
await connection.manager.save(photo1);
const photo2 = new Photo();
photo2.url = "me-and-bears.jpg";
photo2.user = user;
await connection.manager.save(photo2);
With cascades enabled you can save this relation with only one save
call.
To load a user with photos inside you must specify the relation in FindOptions
:
Copy const userRepository = connection.getRepository(User);
const users = await userRepository.find({ relations: ["photos"] });
// or from inverse side
const photoRepository = connection.getRepository(Photo);
const photos = await photoRepository.find({ relations: ["user"] });
Or using QueryBuilder
you can join them:
Copy const users = await connection
.getRepository(User)
.createQueryBuilder("user")
.leftJoinAndSelect("user.photos", "photo")
.getMany();
// or from inverse side
const photos = await connection
.getRepository(Photo)
.createQueryBuilder("photo")
.leftJoinAndSelect("photo.user", "user")
.getMany();
With eager loading enabled on a relation you don't have to specify relation or join it - it will ALWAYS be loaded automatically.