mirror of
https://github.com/typeorm/typeorm.git
synced 2025-12-08 21:26:23 +00:00
added some relations docs
This commit is contained in:
parent
c5d1b21c90
commit
d4cb010875
18
README.md
18
README.md
@ -426,7 +426,7 @@ createConnection(/*...*/).then(connection => {
|
||||
photo.isPublished = true;
|
||||
|
||||
return connection.manager
|
||||
.persist(photo)
|
||||
.save(photo)
|
||||
.then(photo => {
|
||||
console.log("Photo has been saved");
|
||||
});
|
||||
@ -451,7 +451,7 @@ createConnection(/*...*/).then(async connection => {
|
||||
photo.views = 1;
|
||||
photo.isPublished = true;
|
||||
|
||||
await connection.manager.persist(photo);
|
||||
await connection.manager.save(photo);
|
||||
console.log("Photo has been saved");
|
||||
|
||||
}).catch(error => console.log(error));
|
||||
@ -501,7 +501,7 @@ createConnection(/*...*/).then(async connection => {
|
||||
|
||||
let photoRepository = connection.getRepository(Photo);
|
||||
|
||||
await photoRepository.persist(photo);
|
||||
await photoRepository.save(photo);
|
||||
console.log("Photo has been saved");
|
||||
|
||||
let savedPhotos = await photoRepository.find();
|
||||
@ -556,7 +556,7 @@ createConnection(/*...*/).then(async connection => {
|
||||
/*...*/
|
||||
let photoToUpdate = await photoRepository.findOneById(1);
|
||||
photoToUpdate.name = "Me, my friends and polar bears";
|
||||
await photoRepository.persist(photoToUpdate);
|
||||
await photoRepository.save(photoToUpdate);
|
||||
|
||||
}).catch(error => console.log(error));
|
||||
```
|
||||
@ -677,10 +677,10 @@ createConnection(/*...*/).then(async connection => {
|
||||
let metadataRepository = connection.getRepository(PhotoMetadata);
|
||||
|
||||
// First we should persist a photo
|
||||
await photoRepository.persist(photo);
|
||||
await photoRepository.save(photo);
|
||||
|
||||
// Photo is saved. Now we need to persist a photo metadata
|
||||
await metadataRepository.persist(metadata);
|
||||
await metadataRepository.save(metadata);
|
||||
|
||||
// Done
|
||||
console.log("Metadata is saved, and relation between metadata and photo is created in the database too");
|
||||
@ -841,7 +841,7 @@ createConnection(options).then(async connection => {
|
||||
let photoRepository = connection.getRepository(Photo);
|
||||
|
||||
// Persisting a photo also persist the metadata
|
||||
await photoRepository.persist(photo);
|
||||
await photoRepository.save(photo);
|
||||
|
||||
console.log("Photo is saved, photo metadata is saved too.")
|
||||
|
||||
@ -1016,10 +1016,10 @@ let photoRepository = connection.getRepository(Photo);
|
||||
// First save a first photo
|
||||
// We only save the photos, albums are persisted
|
||||
// automatically because of cascade options
|
||||
await photoRepository.persist(photo1);
|
||||
await photoRepository.save(photo1);
|
||||
|
||||
// Second save a first photo
|
||||
await photoRepository.persist(photo2);
|
||||
await photoRepository.save(photo2);
|
||||
|
||||
console.log("Both photos have been saved");
|
||||
```
|
||||
|
||||
@ -1,85 +0,0 @@
|
||||
# Columns
|
||||
|
||||
* What is Entity Column?
|
||||
* Primary columns
|
||||
* Column types
|
||||
* Column types for `mysql` / `mariadb`
|
||||
* Column types for `postgres`
|
||||
* Column types for `sqlite` / `websql`
|
||||
* Column types for `mssql`
|
||||
* Column types for `mongodb`
|
||||
|
||||
## What is Entity Column?
|
||||
|
||||
Entity is a class that maps into database table (or collection for MongoDB database).
|
||||
You can create entity by defining a new class and mark with special orm decorator:
|
||||
|
||||
```typescript
|
||||
import {Entity, PrimaryGeneratedColumn, Column} from "typeorm";
|
||||
|
||||
@Entity()
|
||||
export class User {
|
||||
|
||||
@PrimaryGeneratedColumn()
|
||||
id: number;
|
||||
|
||||
@Column()
|
||||
firstName: string;
|
||||
|
||||
@Column()
|
||||
lastName: string;
|
||||
|
||||
@Column()
|
||||
isActive: boolean;
|
||||
|
||||
}
|
||||
```
|
||||
|
||||
This will create following database table:
|
||||
|
||||
```shell
|
||||
+-------------+--------------+----------------------------+
|
||||
| user |
|
||||
+-------------+--------------+----------------------------+
|
||||
| id | int(11) | PRIMARY KEY AUTO_INCREMENT |
|
||||
| firstName | varchar(255) | |
|
||||
| lastName | varchar(255) | |
|
||||
| isActive | boolean | |
|
||||
+-------------+--------------+----------------------------+
|
||||
```
|
||||
|
||||
Basic entity consist of columns and relations.
|
||||
Each entity **MUST** have a primary column (or ObjectId column if are using MongoDB).
|
||||
|
||||
Each entity must be registered in your connection options this way:
|
||||
|
||||
```typescript
|
||||
import {createConnection, Connection} from "typeorm";
|
||||
import {User} from "./entity/User";
|
||||
|
||||
const connection: Connection = await createConnection({
|
||||
type: "mysql",
|
||||
host: "localhost",
|
||||
port: 3306,
|
||||
username: "test",
|
||||
password: "test",
|
||||
database: "test",
|
||||
entities: [User]
|
||||
});
|
||||
```
|
||||
|
||||
Or you can specify the whole directory with all entities inside - and all of them will be loaded:
|
||||
|
||||
```typescript
|
||||
import {createConnection, Connection} from "typeorm";
|
||||
|
||||
const connection: Connection = await createConnection({
|
||||
type: "mysql",
|
||||
host: "localhost",
|
||||
port: 3306,
|
||||
username: "test",
|
||||
password: "test",
|
||||
database: "test",
|
||||
entities: ["entity/*.js"]
|
||||
});
|
||||
```
|
||||
@ -2,10 +2,186 @@
|
||||
|
||||
* What are relations
|
||||
* One-to-one relation
|
||||
* Many-to-one / One-to-many relations
|
||||
* Many-to-one / one-to-many relations
|
||||
* Many-to-many relation
|
||||
* Having both relation and relation column
|
||||
* How to load relations in entities
|
||||
* Self referencing
|
||||
* Relation options
|
||||
* Lazy relations
|
||||
* Eager relations
|
||||
* Usage examples
|
||||
* Usage examples
|
||||
|
||||
## What are relations
|
||||
|
||||
Relations helps to work with related entities easily.
|
||||
There are several types of relations:
|
||||
|
||||
* one-to-one using `@OneToOne` decorator
|
||||
* many-to-one using `@ManyToOne` decorator
|
||||
* one-to-many using `@OneToMany` decorator
|
||||
* many-to-many using `@ManyToMany` decorator
|
||||
|
||||
## One-to-one relation
|
||||
|
||||
Let's create an example of one-to-one relation between `User` and `Profile`.
|
||||
User can have a single profile and single profile can be one for a single user.
|
||||
|
||||
```typescript
|
||||
import {Entity, PrimaryGeneratedColumn, Column} from "typeorm";
|
||||
|
||||
@Entity()
|
||||
export class Profile {
|
||||
|
||||
@PrimaryGeneratedColumn()
|
||||
id: number;
|
||||
|
||||
@Column()
|
||||
gender: string;
|
||||
|
||||
@Column()
|
||||
photo: string;
|
||||
|
||||
}
|
||||
```
|
||||
|
||||
```typescript
|
||||
import {Entity, PrimaryGeneratedColumn, Column, OneToOne, JoinColumn} from "typeorm";
|
||||
|
||||
@Entity()
|
||||
export class User {
|
||||
|
||||
@PrimaryGeneratedColumn()
|
||||
id: number;
|
||||
|
||||
@Column()
|
||||
name: string;
|
||||
|
||||
@OneToOne(type => Profile)
|
||||
@JoinColumn()
|
||||
profile: Profile;
|
||||
|
||||
}
|
||||
```
|
||||
|
||||
Here we added `@OneToOne` decorator to the `profile` property and specified target relation type `Profile` to it.
|
||||
We also added `@JoinColumn` decorator which is required and must be set only on one side of relation.
|
||||
On which side you set `@JoinColumn` that side's table will contain "relation id" and foreign keys to target entity table.
|
||||
In our example we had one-side-only relation.
|
||||
|
||||
This example will produce following tables:
|
||||
|
||||
```shell
|
||||
+-------------+--------------+----------------------------+
|
||||
| profile |
|
||||
+-------------+--------------+----------------------------+
|
||||
| id | int(11) | PRIMARY KEY AUTO_INCREMENT |
|
||||
| gender | varchar(255) | |
|
||||
| photo | varchar(255) | |
|
||||
+-------------+--------------+----------------------------+
|
||||
|
||||
+-------------+--------------+----------------------------+
|
||||
| user |
|
||||
+-------------+--------------+----------------------------+
|
||||
| id | int(11) | PRIMARY KEY AUTO_INCREMENT |
|
||||
| name | varchar(255) | |
|
||||
| profileId | int(11) | FOREIGN KEY |
|
||||
+-------------+--------------+----------------------------+
|
||||
```
|
||||
|
||||
Again, `@JoinColumn` must be set only on one side of relation - which side must have foreign key in the database table.
|
||||
|
||||
Example how to save such relation:
|
||||
|
||||
```typescript
|
||||
const profile = new Profile();
|
||||
profile.gender = "male";
|
||||
profile.photo = "me.jpg";
|
||||
await connection.manager.save(profile);
|
||||
|
||||
const user = new User();
|
||||
user.profile = profile;
|
||||
await connection.manager.save(profile);
|
||||
```
|
||||
|
||||
With cascades enabled you can save this relation with only one `save` call.
|
||||
|
||||
To load user with profile inside you must specify relation in `FindOptions`:
|
||||
|
||||
```typescript
|
||||
const userRepository = connection.getRepository(User);
|
||||
const users = await userRepository.find({ relations: ["profile"] });
|
||||
```
|
||||
|
||||
Or using `QueryBuilder` you can join them:
|
||||
|
||||
```typescript
|
||||
const users = await connection
|
||||
.getRepository(User)
|
||||
.createQueryBuilder("user")
|
||||
.leftJoinAndSelect("user.profile", "profile")
|
||||
.getMany();
|
||||
```
|
||||
|
||||
With eager loading enabled on a relation you don't have to specify relation or join it - it will be loaded automatically ALWAYS.
|
||||
|
||||
Relations can be uni-directional and bi-directional.
|
||||
Uni-directional are relations with relation decorator only on one side.
|
||||
Bi-directional are relations with decorators on both sides of a relation.
|
||||
|
||||
We just created a uni-directional relation. Let's make it bi-directional:
|
||||
|
||||
```typescript
|
||||
import {Entity, PrimaryGeneratedColumn, Column} from "typeorm";
|
||||
|
||||
@Entity()
|
||||
export class Profile {
|
||||
|
||||
@PrimaryGeneratedColumn()
|
||||
id: number;
|
||||
|
||||
@Column()
|
||||
gender: string;
|
||||
|
||||
@Column()
|
||||
photo: string;
|
||||
|
||||
@OneToOne(type => User, user => user.profile) // specify inverse side as a second parameter
|
||||
user: User;
|
||||
|
||||
}
|
||||
```
|
||||
|
||||
```typescript
|
||||
import {Entity, PrimaryGeneratedColumn, Column, OneToOne, JoinColumn} from "typeorm";
|
||||
|
||||
@Entity()
|
||||
export class User {
|
||||
|
||||
@PrimaryGeneratedColumn()
|
||||
id: number;
|
||||
|
||||
@Column()
|
||||
name: string;
|
||||
|
||||
@OneToOne(type => Profile, profile => profile.user) // specify inverse side as a second parameter
|
||||
@JoinColumn()
|
||||
profile: Profile;
|
||||
|
||||
}
|
||||
```
|
||||
|
||||
We just made our relation bi-directional. Note, inverse relation does not have a `@JoinColumn` decorator.
|
||||
As we already told you `@JoinColumn` must be only on one side of the relation - which table will own a foreign key.
|
||||
|
||||
Bi-directional relations allow you to join relations from both sides using `QueryBuilder`:
|
||||
|
||||
```typescript
|
||||
const profiles = await connection
|
||||
.getRepository(Profile)
|
||||
.createQueryBuilder("profile")
|
||||
.leftJoinAndSelect("profile.user", "user")
|
||||
.getMany();
|
||||
```
|
||||
|
||||
## Many-to-one / one-to-many relations
|
||||
Loading…
x
Reference in New Issue
Block a user