๐Ÿ”ฅPrisma ๋ชจ๋ธ๋ง ์‹ค์Šต: ERD์™€ SQL๋กœ ์ง์ ‘ ๋งŒ๋“ค์–ด๋ณด๊ธฐ

Jisunminยท2025๋…„ 6์›” 22์ผ
post-thumbnail

๋งŒ๋“ค๊ณ ์ž ํ•œ ํ”„๋กœ์ ํŠธ ๊ด€๋ฆฌ ์‹œ์Šคํ…œ ๊ตฌ์กฐ ์š”์•ฝ

  • ์‚ฌ์šฉ์ž(User)๋Š” ์—ฌ๋Ÿฌ ํ”„๋กœ์ ํŠธ(Project)๋ฅผ ๊ด€๋ฆฌํ•˜๊ฑฐ๋‚˜ ์ฐธ์—ฌํ•ฉ๋‹ˆ๋‹ค.
  • ๊ฐ ํ”„๋กœ์ ํŠธ(Project)๋Š” ์—ฌ๋Ÿฌ ์ž‘์—…(Task)์„ ํฌํ•จํ•ฉ๋‹ˆ๋‹ค.
  • ์ž‘์—…(Task)์—๋Š” ์—ฌ๋Ÿฌ ๋Œ“๊ธ€(Comment)์ด ๋‹ฌ๋ฆด ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ฆ‰, ์‚ฌ์šฉ์ž โ†’ ํ”„๋กœ์ ํŠธ โ†’ ์ž‘์—… โ†’ ๋Œ“๊ธ€ ์ˆœ์œผ๋กœ ์—ฐ๊ฒฐ๋˜๋Š” ๊ธฐ๋ณธ์ ์ธ ํ”„๋กœ์ ํŠธ ๊ด€๋ฆฌ ์‹œ์Šคํ…œ ๊ตฌ์กฐ์ž…๋‹ˆ๋‹ค.

์ด๋ฒˆ์— ์ž‘์„ฑํ•œ DB ์Šคํ‚ค๋งˆ๋Š” ์ด๋Ÿฌํ•œ ๊ด€๊ณ„์„ฑ์„ ๊ณ ๋ คํ•˜์—ฌ ์„ค๊ณ„ํ•ด๋ดค์Šต๋‹ˆ๋‹ค.
์ถ”๊ฐ€๋กœ ๋ณด์™„ํ•  ๋ถ€๋ถ„์ด ์žˆ์„ ์ˆ˜ ์žˆ์œผ๋‚˜, ์ดˆ๊ธฐ ๊ธฐํš ๋‹จ๊ณ„๋ผ๊ณ  ์ƒ๊ฐํ•˜์‹œ๊ณ  ๋ด์ฃผ์‹œ๋ฉด ์ข‹์„ ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค.

1. ERD ์ž‘์„ฑ ๋ฐ SQL ์ƒ์„ฑ

  • ERD ์ž‘์„ฑ ๋„๊ตฌ: ERD Cloud๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ๋ชจ๋ธ๋ง์„ ์ง„ํ–‰ํ–ˆ์Šต๋‹ˆ๋‹ค.
  • ERD Cloud์—์„œ ์ž‘์„ฑ ํ›„, Export โ†’ SQL Preview๋ฅผ ํ†ตํ•ด ์•„๋ž˜์™€ ๊ฐ™์€ SQL ์Šคํ‚ค๋งˆ๋ฅผ ์–ป์—ˆ์Šต๋‹ˆ๋‹ค.
CREATE TABLE `user` (
	`id`	serial	NOT NULL,
	`userId`	string	NULL,
	`password`	string	NULL,
	`name`	string	NULL
);

CREATE TABLE `project` (
	`id`	serial	NOT NULL,
	`projectId`	string	NULL,
	`progress`	int	NULL,
	`deadline`	DateTime	NULL,
	`managerId`	serial	NOT NULL
);

CREATE TABLE `comment` (
	`id`	serial	NULL,
	`comment`	string	NULL,
	`user_id`	serial	NOT NULL,
	`task_id`	serial	NOT NULL
);

CREATE TABLE `task` (
	`id`	serial	NOT NULL,
	`title`	string	NULL,
	`desc`	string	NULL,
	`status`	string	NULL,
	`user_ id`	serial	NOT NULL,
	`projectId`	serial	NOT NULL,
	`manager_id`	serial	NOT NULL
);

ALTER TABLE `user` ADD CONSTRAINT `PK_USER` PRIMARY KEY (
	`id`
);

ALTER TABLE `project` ADD CONSTRAINT `PK_PROJECT` PRIMARY KEY (
	`id`
);

ALTER TABLE `task` ADD CONSTRAINT `PK_TASK` PRIMARY KEY (
	`id`
);

2. Prisma ๋ชจ๋ธ๋กœ ๋ณ€ํ™˜ํ•˜๊ธฐ

์œ„ SQL ์Šคํ‚ค๋งˆ๋ฅผ ์ฐธ๊ณ ํ•˜์—ฌ Prisma ๋ชจ๋ธ ์ •์˜ ์‹œ ์ž์ฃผ ์‚ฌ์šฉํ•˜๋Š” ์†์„ฑ๋“ค์„ ์ ์šฉํ•ด ๋ชจ๋ธ์„ ์ž‘์„ฑํ•ฉ๋‹ˆ๋‹ค.

์ฃผ์š” Prisma ์†์„ฑ

  • @id: ๊ธฐ๋ณธ ํ‚ค (Primary Key)
  • @default(autoincrement()): ์ž๋™ ์ฆ๊ฐ€ ๊ฐ’
  • @unique: ์œ ๋‹ˆํฌ ์ œ์•ฝ ์กฐ๊ฑด
  • ?: Optional ํ•„๋“œ (nullable ํ—ˆ์šฉ)
  • ๊ด€๊ณ„ ํ•„๋“œ ๋ฐ @relation ์„ค์ • ๋“ฑ

3. Prisma ๋ชจ๋ธ ์ž‘์„ฑ ์‹œ๋„ ์ •๋ฆฌ

๐Ÿงญ ์ž‘์„ฑ ๋‹จ๊ณ„ ์š”์•ฝ

1๋‹จ๊ณ„: ๋ชจ๋“  field ์ •์˜

๊ฐ ๋ชจ๋ธ์˜ ํ•„๋“œ๋“ค์„ ๋จผ์ € ์ •์˜ํ•˜์˜€์Œ (id, userId, title, desc ๋“ฑ).

2๋‹จ๊ณ„: ์ผ๋Œ€๋‹ค ๊ด€๊ณ„์˜ "๋‹ค" ์ชฝ ์ •์˜

Comment, Task ๋“ฑ์˜ ๋ชจ๋ธ์—์„œ ์™ธ๋ž˜ ํ‚ค ํ•„๋“œ ์ •์˜ (user_id, project_id, manager_id ๋“ฑ).
์ด ์‹œ์ ์—๋Š” ๊ด€๊ณ„ ์„ค์ •์ด ๋ช…ํ™•ํžˆ ์•ˆ ๋˜์–ด ์žˆ์Œ.

3๋‹จ๊ณ„: ์ผ๋Œ€๋‹ค ๊ด€๊ณ„์˜ "์ผ" ์ชฝ ์ •์˜

๊ด€๊ณ„๋ฅผ ๋ช…ํ™•ํžˆ ์ง€์ •ํ•˜๊ธฐ ์œ„ํ•ด @relation ์†์„ฑ์„ ์‚ฌ์šฉํ•˜์—ฌ ์ฐธ์กฐ ์—ฐ๊ฒฐ.
๊ทธ๋ฆฌ๊ณ  ์ฐธ์กฐ๋ฅผ ํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” ์ž‘์„ฑํ•˜์ง€ ์•Š์€ ์™ธ๋ž˜ํ‚ค๋„ ์ž‘์„ฑํ•ด์•ผ ํ•˜๋Š”๊ฒƒ์„ ๊บ ๋‹ซ๊ณ  ์ถ”๊ฐ€ํ•˜์˜€์Œ

1๋‹จ๊ณ„: ๋ชจ๋“  ํ•„๋“œ ์ •์˜

model User {
  id       Int    @id @default(autoincrement())
  userId   String @unique
  password String 
  name     String
}

model Project {
  id         Int    @id @default(autoincrement())
  projectId  String @unique
  progress   Int
  deadline   DateTime
  managerId  String
}

model Task {
  id         Int    @id @default(autoincrement())
  title      String
  desc       String
  status     String

  user_id    
  project_id 
  manager_id 
}

model Comment {
  id       Int    @id @default(autoincrement())
  comment  String

  user_id  
  task_id  
}

2๋‹จ๊ณ„: "๋‹ค"์ชฝ์˜ ๊ด€๊ณ„ ์ •์˜ ์ถ”๊ฐ€

model User {
  id       Int    @id @default(autoincrement())
  userId   String @unique
  password String 
  name     String

  comments Comment[]
  projects Project[]
  tasks    Task[]
}

model Project {
  id         Int    @id @default(autoincrement())
  projectId  String @unique
  progress   Int
  deadline   DateTime
  managerId  String

  tasks Task[]
}

model Task {
  id         Int    @id @default(autoincrement())
  title      String
  desc       String
  status     String

  user_id    
  project_id 
  manager_id 

  comments Comment[] 
}

model Comment {
  id       Int    @id @default(autoincrement())
  comment  String

  user_id  
  task_id  
}

3๋‹จ๊ณ„: "์ผ"์ชฝ ๊ด€๊ณ„ ์ •์˜ ์ถ”๊ฐ€

model User {
  id       Int    @id @default(autoincrement())
  userId   String @unique
  password String 
  name     String

  comments Comment[]
  projects Project[]
  tasks    Task[]
}

model Project {
  id         Int    @id @default(autoincrement())
  projectId  String @unique 
  progress   Int
  deadline   DateTime
  managerId  String

  tasks   Task[]
  manager User @relation(fields: [managerId], references: [id]) 
}

model Task {
  id         Int    @id @default(autoincrement())
  title      String
  desc       String
  status     String
  projectId  Int
  userId     Int
  managerId  Int

  user    User    @relation(fields: [userId], references: [id])
  project Project @relation(fields: [projectId], references: [id])
  manager User    @relation(fields: [projectId], references: [id])

  comments Comment[]  
}

model Comment {
  id       Int    @id @default(autoincrement())
  comment  String
  userId   Int
  taskId   Int

  user User @relation(fields: [userId], references: [id])
  task Task @relation(fields: [taskId], references: [id])
}

โŒ ์ฃผ์š” ๋ฌธ์ œ์  ์š”์•ฝ

1. โ— Ambiguous Relation: ๋™์ผ ๋ชจ๋ธ(User)์— ๋Œ€ํ•œ ๋‹ค์ค‘ ๊ด€๊ณ„ ๋ช…์‹œ ์•ˆ๋จ

Task ๋ชจ๋ธ์—์„œ user์™€ manager ๋ชจ๋‘ User๋ฅผ ์ฐธ์กฐํ–ˆ์ง€๋งŒ, @relation("...") ๋ช…์‹œ๊ฐ€ ์—†์—ˆ์Œ โ†’ ์—๋Ÿฌ ๋ฐœ์ƒ

Error: Ambiguous relation detected...
โœ… ํ•ด๊ฒฐ: @relation("TaskManager") ์ฒ˜๋Ÿผ ์ด๋ฆ„์„ ๋ช…์‹œํ•ด์•ผ Prisma๊ฐ€ ๊ตฌ๋ถ„ ๊ฐ€๋Šฅ

2. โ— Project์˜ managerId ํ•„๋“œ ํƒ€์ž… ๋ถˆ์ผ์น˜

managerId String // โŒ ์ดˆ๊ธฐ์—๋Š” ์ด๋ ‡๊ฒŒ ๋˜์–ด ์žˆ์—ˆ์Œ
ํ•˜์ง€๋งŒ User.id๋Š” Int์ด๋ฏ€๋กœ ํƒ€์ž… ๋ถˆ์ผ์น˜ โ†’ ๊ด€๊ณ„ ์„ค์ • ๋ถˆ๊ฐ€๋Šฅ

3. โ— ์ž˜๋ชป๋œ ํ•„๋“œ ์—ฐ๊ฒฐ

manager User @relation(fields: [projectId], references: [id])

  • manager ๊ด€๊ณ„์— projectId๋ฅผ ์‚ฌ์šฉํ•ด์„œ User๋ฅผ ์ฐธ์กฐํ•˜๋Š” ๊ตฌ์กฐ โ†’ ๋…ผ๋ฆฌ์  ์˜ค๋ฅ˜
  • managerId๋ฅผ ๊ธฐ์ค€์œผ๋กœ ๊ด€๊ณ„ ๋งบ๋Š” ๊ฒŒ ์˜ฌ๋ฐ”๋ฆ„

4. ๐ŸŽฏ Prisma ์Šคํ‚ค๋งˆ ์™„์„ฑ๋ณธ

model User {
  id            Int     @id @default(autoincrement())
  userId        String  @unique
  password      String
  name          String

  tasks         Task[]     @relation("AssignedUser")     // ๋‚ด๊ฐ€ ๋งก์€ ์ผ
  managedTasks  Task[]     @relation("ManagingUser")     // ๋‚ด๊ฐ€ ๊ด€๋ฆฌํ•˜๋Š” ์ผ
  comments      Comment[]
  projects      Project[]  @relation("ProjectManager")   // ๋‚ด๊ฐ€ ๋‹ด๋‹นํ•˜๋Š” ํ”„๋กœ์ ํŠธ๋“ค
}

model Project {
  id         Int     @id @default(autoincrement())
  projectId  String  @unique
  progress   Int
  deadline   DateTime
  managerId  Int

  manager    User     @relation("ProjectManager", fields: [managerId], references: [id])
  tasks      Task[]
}

model Task {
  id         Int     @id @default(autoincrement())
  title      String
  desc       String
  status     String
  projectId  Int
  userId     Int
  managerId  Int

  user       User     @relation("AssignedUser", fields: [userId], references: [id])
  manager    User     @relation("ManagingUser", fields: [managerId], references: [id])
  project    Project  @relation(fields: [projectId], references: [id])
  comments   Comment[]
}

model Comment {
  id        Int     @id @default(autoincrement())
  comment   String
  userId    Int
  taskId    Int

  user      User    @relation(fields: [userId], references: [id])
  task      Task    @relation(fields: [taskId], references: [id])
}

SQL์„ ํ† ๋Œ€๋กœ ๋งŒ๋“  model ์ž…๋‹ˆ๋‹ค. ํ•„์š”์— ๋”ฐ๋ผ @unique ์™€ not Null๋ฅผ ์ถ”๊ฐ€ํ–ˆ์Šต๋‹ˆ๋‹ค.

๐Ÿ“˜Prisma ๋ชจ๋ธ ๋ณ€ํ™˜ ์„ค๋ช…

โœ… ๊ธฐ๋ณธ ๋ณ€ํ™˜ ๊ทœ์น™

  • serial โ†’ Int @default(autoincrement())
    SQL์˜ serial ํƒ€์ž…์€ Prisma์—์„œ Int @default(autoincrement())๋กœ ๋ณ€ํ™˜๋ฉ๋‹ˆ๋‹ค.
    โ†’ ์ž๋™ ์ฆ๊ฐ€ํ•˜๋Š” ์ •์ˆ˜ํ˜• ๊ธฐ๋ณธ ํ‚ค๋ฅผ ์˜๋ฏธํ•ฉ๋‹ˆ๋‹ค.

  • string NULL โ†’ String?
    SQL์—์„œ string NULL๋กœ ์ •์˜๋œ ํ•„๋“œ๋Š” Prisma์—์„œ๋Š” String? (์„ ํƒ์  ํ•„๋“œ)๋กœ ์ฒ˜๋ฆฌํ•ฉ๋‹ˆ๋‹ค.
    โ†’ ๊ฐ’์ด ์—†์–ด๋„ ๋˜๋Š” optional ํ•„๋“œ์ž…๋‹ˆ๋‹ค.


โœ… ์™ธ๋ž˜ํ‚ค ํ•„๋“œ ๋ฐ ๊ด€๊ณ„ ์„ค์ •

  • ๊ธฐ๋ณธ ์™ธ๋ž˜ํ‚ค ๊ด€๊ณ„
    SQL์˜ ์™ธ๋ž˜ํ‚ค ํ•„๋“œ๋Š” Prisma์—์„œ ๋‹ค์Œ๊ณผ ๊ฐ™์ด ํ‘œํ˜„๋ฉ๋‹ˆ๋‹ค:

    userId Int
    user User @relation(fields: [userId], references: [id])
    โ†’ userId๋Š” ์™ธ๋ž˜ํ‚ค ํ•„๋“œ์ด๋ฉฐ, ์‹ค์ œ ๊ด€๊ณ„๋Š” @relation์œผ๋กœ ์ •์˜๋ฉ๋‹ˆ๋‹ค.

๐Ÿ“Œ Comment ๋ชจ๋ธ ์˜ˆ์‹œ

Comment๋Š” User์™€ Task๋ฅผ ์ฐธ์กฐํ•ฉ๋‹ˆ๋‹ค:

model Comment {
  id       Int    @id @default(autoincrement())
  comment  String?
  userId   Int
  taskId   Int

  user     User @relation(fields: [userId], references: [id])
  task     Task @relation(fields: [taskId], references: [id])
}

โœ… ํ•„๋“œ๋ช… ๋งคํ•‘: @map

SQL์—์„œ๋Š” ์ข…์ข… ํ•„๋“œ๋ช…์ด user_id์ฒ˜๋Ÿผ snake_case๋กœ ๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค.
Prisma์—์„œ๋Š” camelCase(userId)๋กœ ํ•„๋“œ๋ช…์„ ๋ฐ”๊พธ๋˜, ์‹ค์ œ DB ์ปฌ๋Ÿผ๋ช…๊ณผ ๋งคํ•‘ํ•ด์ฃผ๊ธฐ ์œ„ํ•ด @map()์„ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.

์˜ˆ์‹œ:

userId Int @map("user_id")

โœ… ๋‹ค์ค‘ ๊ด€๊ณ„(@relation("...")) ๋ช…์‹œ

Prisma์—์„œ๋Š” ํ•˜๋‚˜์˜ ๋ชจ๋ธ์ด ๋™์ผํ•œ ๋Œ€์ƒ ๋ชจ๋ธ์„ ๋‘ ๋ฒˆ ์ด์ƒ ์ฐธ์กฐํ•˜๋ฉด ์•„๋ž˜์™€ ๊ฐ™์€ ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค:

Error validating model "Task": Ambiguous relation detected...

์ด๋ฅผ ํ•ด๊ฒฐํ•˜๋ ค๋ฉด ๊ฐ ๊ด€๊ณ„์— ๋ช…ํ™•ํ•œ ์ด๋ฆ„์„ ๋ช…์‹œํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

์˜ˆ์‹œ:

model Task {
  managerId Int
  userId    Int

  user    User @relation(fields: [userId], references: [id])
  manager User @relation("TaskManager", fields: [managerId], references: [id])
}

model User {
  tasksManaged Task[] @relation("TaskManager")
}

โžก๏ธ @relation("TaskManager")์ฒ˜๋Ÿผ ์ด๋ฆ„์„ ์ง€์ •ํ•˜๋ฉด Prisma๊ฐ€ ๊ด€๊ณ„๋ฅผ ๋ช…ํ™•ํ•˜๊ฒŒ ๊ตฌ๋ถ„ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

โœ… ๋ชจ๋ธ ๊ตฌ์กฐ ์š”์•ฝ ์˜ˆ์‹œ

  • User๋Š” ์—ฌ๋Ÿฌ Task, Comment, Project๋ฅผ ๊ฐ€์งˆ ์ˆ˜ ์žˆ์Œ
  • Project๋Š” ํ•œ ๋ช…์˜ User(manager)๋ฅผ ๊ฐ€์ง
  • Task๋Š” ๋‹ด๋‹น์ž(user)์™€ ๊ด€๋ฆฌ์ž(manager)๋ฅผ ๊ฐ๊ฐ User๋กœ ๊ฐ€์ง
    โ†’ ์ด๋•Œ ๋‹ค์ค‘ ๊ด€๊ณ„ ์ด๋ฆ„์ด ํ•„์š”ํ•จ
  • Comment๋Š” User์™€ Task๋ฅผ ์—ฐ๊ฒฐํ•˜๋Š” ๊ด€๊ณ„ ํ…Œ์ด๋ธ” ์—ญํ• 

๐Ÿ™‹โ€โ™€๏ธ ๋งˆ๋ฌด๋ฆฌ

ERD์™€ SQL์„ ์ฐธ๊ณ ํ•ด Prisma ๋ชจ๋ธ๋กœ ๋ฐ”๊พธ๋ฉด, ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ๊ตฌ์กฐ๋ฅผ ์ฝ”๋“œ๋กœ ์‰ฝ๊ฒŒ ํ‘œํ˜„ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
SQL์„ Prisma ๋ฌธ๋ฒ•์œผ๋กœ ๋ณ€ํ™˜ํ•˜๋Š” ์—ฐ์Šต์„ ํ•˜๊ณ , ์ž˜๋ชป๋œ ๋ถ€๋ถ„์„ ์ฐพ์•„ ์ˆ˜์ •ํ•ด๊ฐ€๋ฉฐ ๊ณต๋ถ€ํ•˜๋ฉด Prisma ๋ชจ๋ธ ์„ค๊ณ„ ๋ฌธ๋ฒ•์— ์ ์  ์ต์ˆ™ํ•ด์งˆ ๊ฑฐ๋ผ๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค.

profile
๋‹จ์ˆœ ์‚ฌ์šฉ์ž๊ฐ€ ์•„๋‹Œ, ์ดํ•ดํ•˜๊ณ  ๋งŒ๋“œ๋Š” ๊ฐœ๋ฐœ์ž๊ฐ€ ๋˜๊ธฐ ์œ„ํ•œ ๊ธฐ๋ก.

0๊ฐœ์˜ ๋Œ“๊ธ€