본문 바로가기
Prisma

[Prisma] 2. Prisma Model 디테일

by spare8433 2025. 1. 12.
mysql 사용 기준으로 작성되어 몇몇 기능 및 지원에 대한 내용이 없을 수 있습니다.

 

Model 설명

데이터 모델은 애플리케이션의 주요 개념(예: 사용자, 게시글, 댓글 등)을 표현하는 객체가 되며 데이터베이스의 테이블에 매핑됩니다.

 

데이터 모델은 Prisma가 자동으로 생성하는 Prisma Client API의 기반이 되어 해당 모델에 대한 CRUD 쿼리 제공자동으로 타입을 정의합니다.







모델 생성

 

Prisma 에서 데이터 모델을 생성하는 방법 2가지

  1. Introspection : 현재 DB 내용을 기준으로 데이터 모델 생성
  2. Model Definition : 데이터 모델을 수동으로 작성하고 DB 에 업데이트



1. Introspection

Prisma CLI 를 사용하여 데이터베이스를 내부적으로 조사하여 Prisma 스키마에서 데이터 모델을 생성할 수 있습니다.

 

Prisma ORM기존 프로젝트에 추가할 때 데이터 모델의 초기 버전을 생성하는 데 주로 사용되며, Prisma Migrate를 사용하지 않고 일반 SQL이나 다른 마이그레이션 도구를 사용하여 스키마 마이그레이션을 수행하는 상황에 활용하는 경우가 일반적입니다.



# 데이터베이스 내용 schema 에 적용
prisma db pull

# 진행 과정
# 1. Prisma 스키마에서 데이터베이스 연결
# 2. 데이터베이스 스키마 읽기(Introspect)
# 3. 데이터베이스 스키마를 Prisma 스키마로 변환 후 Prisma 스키마 파일 업데이트

# 업데이트 된 Prisma 스키마 파일 기준으로 Prisma Client 업데이트
prisma generate





2. Model Definition

model [model name] {
  // Fields Definition
}

// Model exmaple
model Profile  {  
  id         Int      @id  @default(autoincrement())  
  bio         String  
  user         User      @relation(fields:  [userId],  references:  [id])  
  userId     Int      @unique  
}




데이터 베이스와 매핑

// 모델 및 컬럼 매핑

model Comment {
  firstName String @map("first_name") // 데이터베이스 컬럼 이름은 first_name

  @@map("comments") // 데이터베이스 테이블 이름은 "comments"
}



enum(열거형) 매핑 사용 예

enum Role {
  ADMIN
  USER
  GUEST
  @@map("user_roles") // 데이터베이스에서는 'user_roles'라는 이름의 enum(열거형)을 사용
}

model User {
  id   Int    @id @default(autoincrement())
  name String
  role Role   @map("role_column") // 'role' 필드는 데이터베이스에서 'role_column'으로 저장
}





필드 정의

{
    [필드 이름][?(optiona)]        필드 유형    (optional)    선택적 속성
    ...
}

model Comment  {  
  id         Int          @id @default(autoincrement())  
  title     String      @db.VarChar(200) // native database type attributes
  content?     String  
  comments     Comment[]      // [Relation fields] A post can have many comments
}





속성 정의

 

- ID 필드 정의: @id

  • Composite ID(복합 ID) : @@id([firstName, lastName]), @@id(name: "fullName", fields: [firstName, lastName])

 

- 기본값 정의: @default

  • autoincrement: @default(autoincrement())
  • 현재 시간을 기본값으로: @default(now())
  • json type : @default("{ "hello": "world" }")
  • 정적값 배열 : @default([5, 6, 8]), @default(["Hello", "Goodbye"])
  • cuid, uuid : @default(cuid()) @default(uuid())

 

- 유니크 필드 정의: @unique

  • compound unique constraints(복합 고유 제약 조건) : @@unique([authorId, title])

 

- 인덱스 정의: @index

  • multi-column(다중 열 인덱스): @@index([title, content])





enum 정의

model User  {  
    id Int  @id  @default(autoincrement())  
    email String  @unique  
    name String?  
    role Role  @default(USER)  
}  

enum Role  {  
    USER  
    ADMIN  
}



모델 타입 정의

현재 model 구조를 반영해 Prisma Client 가 generate 과정 중 model type 을 정의하며, 정의된 type 은 데이터베이스 쿼리에서 type 의 안정성이 보장되며, 컴파일 시점에 검증되도록 보장






Relations

관계 필드는 Prisma ORM 수준에서 모델 간의 연결을 정의하며 데이터베이스에 존재하지 않습니다.

 

@relation 속성에서 참조하는 필드는 데이터베이스에 존재하며 관계된 테이블을 연결하는 외래 키입니다.



관계 필드

  • relation field : 관계 필드는 스칼라 유형이 아닌 Prisma 모델의 필드입니다. ex) User.posts, Post.author
  • annotated relation field : 관계 필드 중 @relation 을 사용하는 필드 즉 관계에서 외래 키를 저장하는 쪽의 필드를 의미 ex) Post.Author
  • relation scalar field : @relation 의 인자 fields 로 지정된 필드 즉 실제 데이터베이스에 저장되는 외래 키 필드 ex) Post.authorId



// example

model User {
  id    Int    @id @default(autoincrement())
  email String @unique
  role  Role   @default(USER)
  posts Post[] // "relation field" (defined only at the Prisma ORM level)
}

model Post {
  id       Int    @id @default(autoincrement())
  title    String
  author   User   @relation(fields: [authorId], references: [id]) // "annotated relation fields" (uses the relation scalar field `authorId` below)
  authorId Int // "relation scalar field" (used in the `@relation` attribute above)
}




@relation 속성 정의

  • name: 관계의 이름을 정의하며, M-N 관계에서는 중간 테이블의 이름도 결정.
  • fields: 현재 모델에서 외래 키로 사용되는 필드 목록. (annotated relation field 에서 필수)
  • references: 관계된 다른 모델에서 참조하는 필드 목록. (annotated relation field 에서 필수)
  • map: 데이터베이스에서 외래 키의 커스텀 이름을 정의.
  • onUpdate: 참조된 항목이 업데이트될 때 수행할 동작을 정의. (*referential actions)
  • onDelete: 참조된 항목이 삭제될 때 수행할 동작을 정의. (*referential actions)

 

※*referential actions: Cascade, Restrict, NoAction, SetNull, SetDefault




one-to-one (일대일 관계)

model User {
  id      Int      @id @default(autoincrement())
  profile Profile? // "relation field"
}

model Profile {
  id     Int  @id @default(autoincrement())
  user   User @relation(fields: [userId], references: [id]) // "annotated relation field"
  userId Int  @unique // relation scalar field (used in the `@relation` attribute above)
}



다중 필드 관계

model User {
  firstName String
  lastName  String
  profile   Profile?

  @@id([firstName, lastName])
}

model Profile {
  id            Int    @id @default(autoincrement())
  user          User   @relation(fields: [userFirstName, userLastName], references: [firstName, lastName])
  userFirstName String // relation scalar field (used in the `@relation` attribute above)
  userLastName  String // relation scalar field (used in the `@relation` attribute above)

  @@unique([userFirstName, userLastName])
}





one-to-many relations (일대다 관계)

model User {
  id    Int    @id @default(autoincrement())
  posts Post[] // One-to-many relations field
}

model Post {
  id       Int  @id @default(autoincrement())
  author   User @relation(fields: [authorId], references: [id])
  authorId Int
}





many-to-many relations (다대다 관계)

  1. Explicit many-to-many relations: 명시적 다대다 관계
  2. Implicit many-to-many relations: 암시적 다대다 관계



1. Explicit many-to-many relations (명시적 다대다 관계)

다대다 관계의 관계 테이블을 Prisma 스키마 모델로 정의해 사용하는 방식으로 직접적으로 쿼리를 사용할 수 있고 추가적으로 데이터를 저장해야 하는 경우 유용합니다.



model Post {
  id            Int                        @id @default(autoincrement())
  categories     CategoriesOnPosts[] // 명시적(Explicit)관계 표시
}

model Category {
  id    Int                     @id @default(autoincrement())
  posts CategoriesOnPosts[] // 명시적(Explicit)관계 표시
}

// 명시적(Explicit)으로 다대다 관계 테이블 정의
model CategoriesOnPosts {
  post       Post     @relation(fields: [postId], references: [id])
  postId     Int // relation scalar field (used in the `@relation` attribute above)
  category   Category @relation(fields: [categoryId], references: [id])
  categoryId Int // relation scalar field (used in the `@relation` attribute above)
  assignedAt DateTime @default(now())
  assignedBy String

  @@id([postId, categoryId])
}





Implicit many-to-many relations (암시적 다대다 관계)

다대다 관계의 관계 테이블을 Prisma 가 관계 테이블을 간단하게 자동으로 생성해주는 방식으로 추가적인 데이터를 저장할 필요 없을 때 유용합니다.



model Post {
  id         Int        @id @default(autoincrement())
  title      String
  categories Category[] // 암시적(Implicit)관계 표시
}

model Category {
  id    Int    @id @default(autoincrement())
  name  String
  posts Post[] // 암시적(Implicit)관계 표시
}






Multi-file Prisma Schema

Prisma Schema의 generator 블록의 previewFeatures 필드에 prismaSchemaFolder 기능 플래그를 추가하여 사용



// prisma/schema.prisma

generator client {
  provider        = "prisma-client-js"
  previewFeatures = ["prismaSchemaFolder"] // need this line to use Multi-file Prisma Schema

datasource db {
  provider = "postgresql"
  url      = env("DATABASE_URL")
}






// 폴더 구조 예시

my-app/
├─ ...
├─ prisma/
│  ├─ schema/
│  │  ├─ post.prisma
│  │  ├─ schema.prisma
│  │  ├─ user.prisma
├─ ...




※디렉토리 구조 tip

  • 도메인별로 파일을 정리
  • datasourcegenerator 블록을 정의하는 "기본" 스키마 파일 정의 ex) main.prisma, schema.prisma, base.prisma






참고

https://www.prisma.io/docs/orm/prisma-schema/data-model