ORM은 데이터베이스 테이블과 객체 지향 프로그래밍의 클래스 간에 매핑을
When using an entity constructor its arguments must be optional. Since ORM creates instances of entity classes when loading from the database, therefore it is not aware of your constructor arguments.
엔터티에 생성자가 있으면 이건 무조건 선택적이어야 한다.
왜냐면 ORM은 이 과정에서 기본적으로 생성자를 호출하게 되는데, 생성자가 필수 인수를 요구한다면 ORM이 이러한 요구사항을 충족시키기 어렵습니다.
pk 이를 사용하여 엔터티를 저장할 때 save항상 주어진 엔터티 ID(또는 ID)를 사용하여 데이터베이스에서 엔터티를 찾으려고 시도합니다. ID/ID가 발견되면 데이터베이스에서 이 행을 업데이트합니다. 해당 ID가 포함된 행이 없으면 새 행이 삽입됩니다.
const user = await dataSource.manager.findOneBy(User, {
firstName: "Timber",
lastName: "Saw",
})
const user = await dataSource.getRepository(User).findOneBy({
firstName: "Timber",
lastName: "Saw",
})
Delete하면 시간을 왜 기록하지?
SoftDelete에 사용함
await repository.softDelete(id);
const user = await repository.findOneBy({ id: userId });
await repository.softRemove(user);
nullable, default 등등..
엔터티 간에 반복되는 컬럼을 약간 템플릿 처럼 만들어서 쓰는 개념?
import { Column } from "typeorm"
export class Name {
@Column()
first: string
@Column()
last: string
}
import { Entity, PrimaryGeneratedColumn, Column } from "typeorm"
import { Name } from "./Name"
@Entity()
export class User {
@PrimaryGeneratedColumn()
id: string
@Column(() => Name)
name: Name
@Column()
isActive: boolean
}
import { Entity, PrimaryGeneratedColumn, Column } from "typeorm"
import { Name } from "./Name"
@Entity()
export class Employee {
@PrimaryGeneratedColumn()
id: string
@Column(() => Name)
name: Name
@Column()
salary: number
}
import { Entity, PrimaryGeneratedColumn, Column } from "typeorm"
import { Name } from "./Name"
@Entity()
export class Student {
@PrimaryGeneratedColumn()
id: string
@Column(() => Name)
name: Name
@Column()
faculty: string
}
계속해서 중첩해서 할 수도 있음.
이렇게 단순 반복적인 엔터티는 임베디트 엔터티를 사용하면 편리함.
중복을 줄이기 위해 말 그대로 엔터티 자체를 상속
export abstract class Content {
@PrimaryGeneratedColumn()
id: number
@Column()
title: string
@Column()
description: string
}
@Entity()
export class Photo extends Content {
@Column()
size: string
}
@Entity()
export class Question extends Content {
@Column()
answersCount: number
}
@Entity()
export class Post extends Content {
@Column()
viewCount: number
}
모든 인스턴스가 단일 테이블에 저장된다.
(데코레이터 잘 보기)
@Entity()
@TableInheritance({ column: { type: "varchar", name: "type" } })
export class Content {
@PrimaryGeneratedColumn()
id: number
@Column()
title: string
@Column()
description: string
}
@ChildEntity()
export class Photo extends Content {
@Column()
size: string
}
@ChildEntity()
export class Question extends Content {
@Column()
answersCount: number
}
@ChildEntity()
export class Post extends Content {
@Column()
viewCount: number
}
이건 우선 넘어가기
나중에 코드로 필요할 때 살펴보자
데이터베이스 뷰는 하나 이상의 테이블에서 유도된, 저장된 쿼리의 결과로 만들어진 가상 테이블
즉, 미리 복잡한 쿼리를 뷰로 짜 놓고,
서비스단에서는 단순한 호출로 복잡한 쿼리를 추상화해서 호출할 수 있음.
뷰는 읽기 전용이다!
import { ViewEntity, ViewColumn, Connection } from 'typeorm';
@ViewEntity({
expression: (connection: Connection) => connection.createQueryBuilder()
.select("user.id", "id")
.addSelect("user.name", "name")
.from(User, "user")
.where("user.registered = :registered", { registered: true })
})
export class ActiveUser {
@ViewColumn()
id: number;
@ViewColumn()
name: string;
}
이렇게 호출함.
import { getRepository } from 'typeorm';
import { ActiveUser } from './ActiveUser';
async function getActiveUsers() {
const userRepository = getRepository(ActiveUser);
const activeUsers = await userRepository.find();
console.log(activeUsers);
}
음.. 굳이..?
스키마 확장에 장점이 있구나
이건 나중에 클래스로 정의하는 게 진짜 익숙해지면 심화로 살펴보기