Prisma Schema
model 정의
schema.prisma 파일에 필요한 모델을 정의하면 이후 명령어를 통해 데이터베이스 테이블에 매핑할 수 있다. 모델은 이름, 타입, 그리고 어트리뷰트로 구성되어있다. 이름은 각 칼럼의 이름과 매칭되고, 타입은 해당 칼럼에 들어갈 데이터의 타입을 지정하게 된다.
어트리뷰트는 필드에 대한 추가적인 정보를 제공하거나, 특정 동작을 정의하기 위해 사용하는 일종의 메타데이터이다. 이를 통해 데이터베이스의 제약 조건을 정의할 수 있다. 가령 default 어트리뷰트는 해당 필드의 기본값을 지정해줄 수 있고, updatedAt 어트리뷰트는 레코드가 업데이트될 때마다 필드 값을 자동으로 현재 시간으로 설정한다. unique는 필드의 값이 유일해야한다는 제약 조건이고, relation은 모델과 모델간의 관계를 정의한다.
또한 enum을 활용해 특정한 값만 받을 수 있도록 타입을 좁혀 사용할 수도 있다.
model User {
id String @id @default(uuid())
email String @unique
image String?
password String
nickname String
membership Membership @default(BASIC)
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
}
enum Membership {
BASIC
PREMIUM
}
관계 정의
prisma는 SQL 데이터베이스를 대상으로 하고 있다. MySQL이나 PostgreSQL을 흔히 RDB라고 하는데, 이들이 관계 지향 데이터베이스라는 사실을 나타낸다. 따라서 prisma 역시 relation 어트리뷰트를 통해 데이터 간의 관계를 정의하는 방법을 제공하고 있다.
relation 어트리뷰트를 사용하면 테이블과 테이블 사이의 관계를 쉽게 정의할 수 있지만, 실제 데이터베이스에 저장되는 것은 foreign key 뿐이다. 하지만 prismaClient를 사용하면 이러한 관계를 마치 실제 DB에 존재하는 값인 것처럼 접근할 수 있으니 상관 없으려나?
일대다 관계 정의
하나의 장바구니는 여러 제품을 담을 수 있어야 한다. 따라서 장바구니와 제품은 일대다 관계라 볼 수 있다. cartId를 foreign key로 사용하여 서로를 연결하고, CartProducts로 이 관계를 이름지었다. 늘 생각하지만 관계 정의할 때 이름 짓는 것만큼 어려운 게 없다.
model Cart {
products Product[] @relation("CartProducts")
}
model Product {
cart Cart @relation(fields: [cartId], references: [id], name: "CartProducts")
cartId String
}
일대다 관계를 정의할 때는 '다'에 해당하는 모델에 '일'에 해당하는 모델을 가리키는 필드(cart)와 foreign key(cartId)를 정의하는 것이 좋다.
일대일 관계 정의
하나의 유저는 하나의 장바구니를 갖고 있다. 따라서 유저와 장바구니는 일대일 관계라 볼 수 있다. 일대일 관계를 정의할 때는 주종 관계를 잘 파악해서 정의하는 것이 중요하다. 이 경우 유저가 장바구니를 갖는 것이지, 장바구니가 유저를 갖는 것은 아니므로, 장바구니에 필드와 foreign key를 정의했다.
model User {
cart Cart? @relation("UserCart")
}
model Cart {
products Product[] @relation("CartProducts")
user User @relation(fields: [userId], references: [id], name: "UserCart")
userId String @unique
}
User가 반드시 Cart를 가지게 되는 지를 DB 수준에서 보장할 수 없기 때문에 옵셔널 타입으로 지정하여 최소 카디널리티가 0라는 것을 설정해주어야 한다.
다대다 관계 정의
하나의 유저는 여러 제품을 찜할 수 있고, 하나의 제품에 여러 유저가 찜할 수 있다. 따라서 유저와 제품은 다대다 관계라 볼 수 있다. 정션 테이블을 만들어 이를 정의할 수도 있지만, prisma는 훨씬 간단하게 다대다 관계를 정의할 수 있게 해준다.
model User {
cart Cart? @relation("UserCart")
favoriteProducts Product[] @relation("User_Favorite_Product")
}
model Product {
cart Cart @relation(fields: [cartId], references: [id], name: "CartProducts")
cartId String
favoriteUsers User[] @relation("User_Favorite_Product")
}
지금까지의 관계 정의를 정리하면 아래와 같다.
model User {
// 일대일 관계
cart Cart? @relation("UserCart")
// 다대다 관계
favoriteProducts Product[] @relation("User_Favorite_Product")
}
model Cart {
// 일대다 관계
products Product[] @relation("CartProducts")
// 일대일 관계
user User @relation(fields: [userId], references: [id], name: "UserCart")
userId String @unique
}
model Product {
// 일대다 관계
cart Cart @relation(fields: [cartId], references: [id], name: "CartProducts")
cartId String
// 다대다 관계
favoriteUsers User[] @relation("User_Favorite_Product")
}
@relation onDelete
relation 어트리뷰트에는 연결된 데이터가 삭제됐을 때 기존 데이터를 어떻게 처리할지 정하는 onDelete 옵션을 넣어줄 수 있다.
model Cart {
// 일대다 관계
products Product[] @relation("CartProducts")
// 일대일 관계
user User @relation(fields: [userId], references: [id], name: "UserCart", onDelete: Cascade)
userId String @unique
}
- Cascade : 유저가 삭제되면 Cart 데이터도 삭제된다.
- Restrict : Cart 데이터를 삭제하기 전에는 유저를 삭제할 수 없다.
- SetNull : 유저가 삭제되면 userId를 Null로 설정한다. 따라서 user와 userId 모두 옵셔널해야한다.
- SetDefault : 유저가 삭제되면 userId를 디폴트 값으로 설정한다. userId 필드에 @default()를 제공해야 한다.
관계 필드와 foreign key가 필수일 경우 Restrict가 기본값이고, 옵셔널할 경우 SetNull이 기본값이다.
블로그의 정보
Ayden's journal
Beard Weard Ayden