typeORM 공식 문서를 읽으며 작성하였습니다.
데이터베이스의 시작은 table을 생성하는 것이다. 모델을 이용해서 만들 수 있다. 데이터베이스에 model을 저장하기 위해서는, 데이터베이스 테이블이 필요하고 그 DB 테이블은 모델로부터 만들어져야 한다. (but only 엔티티로서 정의한 것들만)
Entity는 @Entity
데코레이터에 의해 decorated된 모델이다. you work with entities everywhere with TypeORM. You can load/insert/update/remove and perform other operations with them.
Let's make our Photo model as an entity:
import { Entity } from "typeorm";
@Entity()
export class Photo {
id: number;
name: string;
description: string;
filename: string;
views: number;
isPublished: boolean;
}
이제 우리는 Photo
entity를 위한 DB table을 만들었다. 하지만 table은 column없이 존재할 순 없으니 column을 만들어보도록 하자.
DB 컬럼을 추가하기 위해서는 @Column
데코레이터를 이용할 수 있다.
또한 각각의 entity는 적어도 하나의 primary key 컬럼을 가져야 한다. @PrimaryColumn
decorator를 이용할 수 있다.
import { Entity, Column, PrimaryColumn } from "typeorm";
@Entity()
export class Photo {
@PrimaryColumn() // PK
id: number;
@Column()
name: string;
@Column()
description: string;
@Column()
filename: string;
@Column()
views: number;
@Column()
isPublished: boolean;
}
auto-generated column은 @PrimaryGeneratedColumn
decorator를 이용한다.
@PrimaryGeneratedColumn()
id: number;
컬럼의 데이터 타입과 limited도 필요에 따라 지정할 수 있다.
괄호 안에 객체 형식으로 작성한다.
import { Entity, Column, PrimaryGeneratedColumn } from "typeorm";
@Entity()
export class Photo {
@PrimaryGeneratedColumn()
id: number;
@Column({ // data types limited
length: 100
})
name: string;
@Column("text")
description: string;
@Column()
filename: string;
@Column("double")
views: number;
@Column()
isPublished: boolean;
}
entity가 만들어지면, DB와 연결을 해줘야 한다.
import "reflect-metadata";
import { createConnection } from "typeorm";
import { Photo } from "./entity/Photo";
createConnection({
type: "mysql",
host: "localhost",
port: 3306,
username: "root",
password: "admin",
database: "test",
entities: [
Photo
],
synchronize: true,
logging: false
}).then(connection => {
// here you can start to work with your entities
}).catch(error => console.log(error));
Setting synchronize makes sure your entities will be synced with the database, every time you run the application.
app을 실행시킬 때마다 DB가 자동으로 동기화되게 해야한다.
Now let's create a new photo to save it in the database:
import { createConnection } from "typeorm";
import { Photo } from "./entity/Photo";
createConnection(/*...*/).then(connection => { // createConnection 메서드를 이용해 DB와 연결
let photo = new Photo();
photo.name = "Me and Bears";
photo.description = "I am near polar bears";
photo.filename = "photo-with-bears.jpg";
photo.views = 1;
photo.isPublished = true;
return connection.manager
.save(photo)
.then(photo => {
console.log("Photo has been saved. Photo id is", photo.id);
});
}).catch(error => console.log(error));
우리는 방금 new photo를 만들고 DB에 저장했다. 이제 우리는 EntityManager
를 사용하여 저장할 수 있다.
import { createConnection } from "typeorm";
import { Photo } from "./entity/Photo";
createConnection(/*...*/).then(async connection => {
/*...*/
let savedPhotos = await connection.manager.find(Photo); // manager.method
console.log("All photos from the db: ", savedPhotos);
}).catch(error => console.log(error));
Now let's refactor our code and use Repository instead of EntityManager. Each entity has its own repository which handles all operations with its entity.
Repositories are more convenient to use than EntityManagers:
import { createConnection } from "typeorm";
import { Photo } from "./entity/Photo";
createConnection(/*...*/).then(async connection => {
let photo = new Photo();
photo.name = "Me and Bears";
photo.description = "I am near polar bears";
photo.filename = "photo-with-bears.jpg";
photo.views = 1;
photo.isPublished = true;
let photoRepository = connection.getRepository(Photo); // getRepository
await photoRepository.save(photo);
console.log("Photo has been saved");
let savedPhotos = await photoRepository.find();
console.log("All photos from the db: ", savedPhotos);
}).catch(error => console.log(error));
Now let's load a single photo from the database, update it and save it:
import { createConnection } from "typeorm";
import { Photo } from "./entity/Photo";
createConnection(/*...*/).then(async connection => {
/*...*/
let photoToUpdate = await photoRepository.findOne(1);
photoToUpdate.name = "Me, my friends and polar bears";
await photoRepository.save(photoToUpdate);
}).catch(error => console.log(error));
그러나 .save
메서드를 이용해서 update 할 수도 있다.
따라서 위의 코드는 이런 식으로 바뀔 수 있다.
let photoToUpdate = await photoRepository.findOne(1);
photoToUpdate.name = "Me, my friends and polar bears";
await photoRepository.save(photoToUpdate);
// .save 메서드 활용
// photoRepository가 미리 DB에 저장되었다고 가정
let photoToUpdate = await photoRepository.findOne(1); // photoRepository DB에서 findone을 한 후
await photoRepository.save([ // find된 항목의 name값을 변경해 save
photoToUpdate.name = "Me, my friends and polar bears"
]);
import { Entity, Column, PrimaryGeneratedColumn, OneToOne, JoinColumn } from "typeorm";
import { Photo } from "./Photo";
@Entity()
export class PhotoMetadata {
@PrimaryGeneratedColumn()
id: number;
@Column("int")
height: number;
@Column("int")
width: number;
@Column()
orientation: string;
@Column()
compressed: boolean;
@Column()
comment: string;
@OneToOne(type => Photo) // @OneToOne decorator
@JoinColumn()
photo: Photo;
}
@OneToOne
decorator를 이용해서 두 개의 entity 사이에서 일대일 관계를 설정할 수 있다.
type => Photo
는 관계를 만들고자 하는 entity의 클래스를 반환하는 함수이다. (class를 직접적으로 쓰는 것이 아니라)
() => Photo
로도 작성할 수 있지만, 가독성을 위해서 위와 같이 작성하였다.
또한 @JoinColumn
decorator도 이용할 수 있다. 관계를 소유한다는 걸 나타내는 데코레이터를 추가하는 것이다. 이 데코레이터는 관계의 소유자 측에 요구된다. 따라서 Photo가 photo_metadata의 차일드가 되는 것이다.
If you run the app, you'll see a newly generated table, and it will contain a column with a foreign key for the photo relation:
+-------------+--------------+----------------------------+
| photo_metadata |
+-------------+--------------+----------------------------+
| id | int(11) | PRIMARY KEY AUTO_INCREMENT |
| height | int(11) | |
| width | int(11) | |
| comment | varchar(255) | |
| compressed | boolean | |
| orientation | varchar(255) | |
| photoId | int(11) | FOREIGN KEY |
+-------------+--------------+----------------------------+
Now let's save a photo, its metadata and attach them to each other.
import { createConnection } from "typeorm";
import { Photo } from "./entity/Photo";
import { PhotoMetadata } from "./entity/PhotoMetadata";
createConnection(/*...*/).then(async connection => {
// 1. create a photo
let photo = new Photo();
photo.name = "Me and Bears";
photo.description = "I am near polar bears";
photo.filename = "photo-with-bears.jpg";
photo.views = 1;
photo.isPublished = true;
// 2. create a photo metadata
let metadata = new PhotoMetadata();
metadata.height = 640;
metadata.width = 480;
metadata.compressed = true;
metadata.comment = "cybershoot";
metadata.orientation = "portrait";
metadata.photo = photo; // this way we connect them
// 3. get entity repositories
let photoRepository = connection.getRepository(Photo);
let metadataRepository = connection.getRepository(PhotoMetadata);
// 4. first we should save a photo
await photoRepository.save(photo);
// 5. photo is saved. Now we need to save a photo metadata
await metadataRepository.save(metadata);
// 6. done
console.log("Metadata is saved, and the relation between metadata and photo is created in the database too");
}).catch(error => console.log(error));
왜냐면 metadata에 photo가 속해있기 때문에 하위 entity를 새로 저장했을 때 자동으로 업데이트가 안되기 때문이다.
안녕하세요 선생님 잘지내셨는지요? typeORM에 관한 좋은 레퍼런스 찾았다 싶었더니 선생님네 벨로그였네요. 즐겨찾기 누르고 가겠읍니다 ~'^'