👩🏻‍💻 TIL

ORM - prisma

ji-hyun 2021. 12. 31. 19:00

이 포스트에서는 ORM 의 기본적인 개념과 장단점을 설명하고 Prisma 의 장단점에 대한 내용을 다룹니다.

 

 

 

 

ORM

프리즈마를 알기 전에 ORM 에 대해서 먼저 알아보자.

ORM (Object-relational mapping)DB 데이터(스키마)를 객체로 매핑해주는 역할

모델링된 객체와 관계를 바탕으로 SQL 을 자동으로 생성해주는 도구

 

 

 

ORM 이란? 다시 말해서,,,
ORM (object-relational mapping) 이란 객체(클래스)와 관계(관계형 데이터베이스) 와의 설정을 의미한다.
객체 지향 프로그래밍클래스를 사용하고 관계형 데이터베이스테이블을 사용한다.

여기서 객체 모델과 관계형 모델 간에 불일치가 존재하는데 이 객체간의 관계를 바탕으로 SQL 을 자동 생성하여
불일치를 해결하는 것이 ORM 이다.

Object <= 매핑 => DB데이터
에서 매핑의 역할을 하는 것이 ORM이라 할 수 있습니다.

 

 

 

 

 

1. ORM 장점

  • 객체 지향적 코드로 인해 더 직관적이고 비즈니스 로직에 집중할 수 있도록 도와준다.
    • CRUD을 위한 긴 SQL 문장을 작성할 필요가 없다. (여전히 쿼리작성은 필요하지만)
    • 각 객체(Model)별로 코드를 작성하여 가독성을 높여 준다.
    • SQL의 절차적 접근이 아닌 객체적인 접근으로 생산성을 높여 준다.
  • 재사용 및 유지보수의 편리성이 증가한다.
    • 매핑 정보가 명확하여, ERD를 보는 것에 대한 의존도를 낮출 수 있다.
    • ORM은 독립적으로 작성이 되어 있고 해당 객체들은 재사용이 가능 하다.
  • DBMS에 대한 종속성이 줄어든다.
    • 대부분의 ORM은 DB에 종속적이지 않다.
    • 개발자는 Object에 집중함으로 DBMS를 교체하는 극단적인 작업에도 비교적 적은 리스크와 시간이 소요된다.
    • 종속적이지 않다는 것은 구현 방법 뿐만 아니라 많은 솔루션에서 자료형 타입까지 유효하다.
    (*종속성: 프로그램 구조가 데이터 구조에 영향을 받는 것을 의미함.)

 

 

 

2. ORM 단점

  • 완벽한 ORM만으로는 구현하기가 어렵다.
    • 사용하기에는 편하지만 설계에는 매우 신중해야 한다.
    • 프로젝트의 복잡성이 높아질 경우 난이도 또한 올라갈 수 있다.
    • 잘못 구현된 경우 속도 저하 및 심한 경우 일관성이 무너지는 문제점이 생길 수 있다.
  • 프로시저가 많은 시스템에서는 ORM의 객체 지향적인 장점을 활용하기 어렵다.
    • 이미 프로시저가 많은 시스템에서는 다시 객체로 바꿔하 하며, 그 과정에서 생산성 저하 혹은 리스크가 발생할 수 있다.

(*프로시저: 특정작업을 위한 프로그램의 일부. 함수와 같은 의미)

 

 

 

 

 

 


이제 ORM Framework로써 Prisma 에 대해 소개 하겠다.

 

 

 

Prisma

Prisma는 기존 ORM과 근본적으로 다른 ORM 이고, 기존 ORM이 겪는 많은 문제들을 겪지 않는다. - prisma docs

 

 

다음으로 소개드릴 ORM은 Prisma 입니다. Prisma 의 특징은 GraphQL 스키마를 기반으로 DB 를 자동생성 해준다는 것입니다. GraphQL이란 facebook에서 만든 Graph Query Language 로 어플리케이션 쿼리 언어로써 기존의 REST API의 한계점을 극복하고자 나온 통신 규약으로 REST API를 대체할 수 있습니다.

 

 

+ 그래프큐엘: 앤드포인트가 하나지만 데이터를 여러개나 하나를 자유자재로 가져올 수 있다...?

REST API 는 갖고 올 데이터를 지정해주어야 함

POST 방식만 사용한다.

 

 

 

 

GraphQL의 장점으로는 다음과 같습니다.

 

1) 요청메세지가 값이 없는 JSON과 비슷하며 받는 데이터는 JSON형태 이다.
2) 단일요청으로 원하는 데이터를 한번에 가져올 수 있다.
3) type system을 지원한다.
4) GraphiQL 등의 강력한 도구를 사용 할 수 있다.
5) 확장성이 좋다.

 

 

 

 

 

 

 

Prisma 의 구성

Prisma는 Prisma는 Schema, Prisma introspect, Prisma migration, Prisma client, Prisma studio로 구성되어 있다.

 

 

 

1. Prisma introspect

prisma 에서는 기존의 데이터베이스를 수작업으로 ORM 에 매핑해줄 필요가 없다.

Database URL 을 설정하고, npx prisma introspect 한번이면 기존의 Database 의 구조를 자동으로 Prisma schema 로 불러올 수 있다.

기존에 있던 Database 에 Prisma를 사용하시려는 분들에게 유용한 기능이다.

 

 

 

2. Prisma Migrate

prisma Migrate 를 이용하면 새로운 테이블을 생성하거나, 기존 테이블에 열을 추가하는 등 Database 를 변경하는 기능(도구)이다.

Prisma schema 를 직접 변경하여 Database 를 변경함으로써, 복잡한 SQL 문을 사용하지 않아도 된다.

 

아래의 코드로 schema를 DB에 반영하고, schema를 기반으로 Prisma Client를 업데이트 할 수 있다.

 

npx prisma migrate save --experimental
npx prisma migrate up --experimental
npx prisma generate

 

 

3. Prisma Client

prisma Client는 데이터에 맞춰 자동 생성되는 쿼리생성기이다. 위에서 정의한 prisma schema 를 기반으로 DB에 요청을 보낼 수 있다. prisma Client 는 꼭 graphQL 과 같이 사용하지 않아도 된다! 기존의 REST API에 prisma를 도입해도 된다.

 

 

 

 

 


Prisma schema 에 대해서 알아보자.

Prisma SchemaGenerator, Data sources, Data Model 3가지로 이루어져 있다.

Prisma Schema 는 schema.prisma 라는 파일을 사용한다.

 

 

 

 

 

1. Prisma schema - Generator

 

코드

 

// schema.prisma 파일
// This is your Prisma schema file,
// learn more about it in the docs: https://pris.ly/d/prisma-schema

generator client {
  provider = "prisma-client-js"
}

generator nexusPrisma {
  provider = "nexus-prisma"
}

datasource db {
  provider = "mysql"    // Database 종류
  url      = env("DATABASE_URL")      // Database url
}


/// 사용자 정보
model User {
  id        Int      @id @default(autoincrement())
  createdAt DateTime @default(now())
  updatedAt DateTime @updatedAt
  /// 사용자 이름
  name      String?
  email     String   @unique
  Post      Post[]
}

/// 포스트
model Post {
  id        Int      @id @default(autoincrement())
  createdAt DateTime @default(now())
  updatedAt DateTime @updatedAt
  user      User?     @relation(fields: [userId], references: [id])
  userId    Int?
  title     String
  content   String?
}

 

generator Prisma 명령(prisma migrate, prisma client)를 실행하는 환경을 결정하는 필드이다.
일반적으로는 provider 외에 설정할 필요가 없다.
그러나 추가로, Preview 기능을 사용하기 위해서는, PrieviewFeatures 옵션을 추가해야 한다.

 

 

generator client {
  provider = "prisma-client-js"
  previewFeatures = []
}

 

현재 Prisma가 지원하는 previewFeatures옵션은 다음과 같다.
nativeTypes microsoftSqlServer

 

 

 

 

 

 

 

 

2. Prisma Schema - Data Source

Data Source란, Prisma를 사용하여 연결할 데이터베이스의 정보를 설정해 주는 필드이다.
필요한 정보로는, Database의 종류(provider)과 Database URL(url)이 있습니다.

 

 

 

 

Data Source는 datasource 필드에서 정의된다.

 

 datasource db{
  provider = Database 종류
  url	= Database  
}

 

 

현재 사용가능한 provider 옵션은 다음과 같다.

 

sqlite postgresql mysql sqlserver

 

 

url

Database 마다 url의 형식이 조금씩 다르다.
url에 직접 URL을 기입할 수도 있고, env("DATABASE_URL")을 사용해
환경변수를 통해 사용할 수 있다.
.env 파일을 통해 관리하는 것을 추천한다.
아래에서 각 Database마다 상세하게 알아보도록 하겠다.

 

 

 

 

MySQL

MySQL의 기본URL은 mysql://USER:PASSWORD@HOST:PORT/DATABASE 이다.
추가로 URL 끝에 ?KEY1=VALUE&KEY2=VALUE의 형식으로 인자를 사용할 수 있다.
인자의 종류가 많아 Prisma Docs 를 참고해주길...

 

 

 

 

 

코드

// .env.example 파일
DATABASE_URL=""

 

 

 

 

 

 

 

 

 

3. Prisma Schema - Data model

PSL(Prisma Schema Language)를 사용하여 작성한다.

 

Model

Database의 테이블에 매핑되는 개념이다.
Field (DB의 column과 동일)가 있고, Field는 Filed Type (DB의 data_type과 동일),
제약조건 (unique, realation(1:n, n:m 관계)) 등이 있습니다.
해당 부분은 추후에 model간의 관계를 설명하면서 더 자세하게 알아보도록 하겠다.
대략적인 구조는 아래와 같다.

 

model ModelName {
    Field1	FieldType @option
    Field2	FieldType
    Field3	FieldType
}
model ModelName { Field1 FieldType @option Field2 FieldType Field3 FieldType } 

 

 

 

 

 

오늘은 Prisma Schema의 구성에 대하여 알아보았다.
다음 포스트에서는 Model의 더욱 구체적인 예시와, 모델간의 관계에 대하여 알아보겠다.

 


Data model 이란

model 을 구성하는 방법은 2가지가 있다.

 

1. Prisma Introspect를 이용하여 기존 Database에서 Model을 가져오기
2. Prisma migration을 이용하여 Prisma Schema로 직접 작성하기
(❗ Prisma migration은 실험기능입니다. 2.13.0 이전버전과 이후 버전은 호환되지 않습니다.)

 

 

1. model

Database의 테이블에 매핑되는 개념이다.
Field (DB의 column과 동일)가 있고, Field는 Filed Type (DB의 data_type과 동일), 제약조건 (unique, realation(1:n, n:m 관계)) 등이 있다.

 

 

 

 

model 이름 매핑

일반적으로 Database의 테이블 이름은 snake_case로 짓지만, prisma의 규칙은 PascalCase 이다.
이런 경우, @@map을 통해 model 이름을 원하는 이름으로 매핑할 수 있다.

 

model user_profiles{
  //Fields
  @@map(name:"UserProfile")
}

 

 

 

2. Field

Database의 column에 매핑되는 개념입니다.
총 6개의 scalar Type과, 사용자가 설정하는 관계필드(외래키)로 구성되어 있습니다.
단수 타입과 List Type (relation 한정)을 가지고 있습니다.
null을 허용하고 싶은경우 Type?을 사용합니다.(❗List Type은 null이 될 수 없습니다.)

 

 

 

 

2.1 Field 속성, 함수

Field 속성에서는 Field가 Database상에서의 key, index 등을 지정할 수 있습니다. Field 함수에서는 자동증가, cuid, uuid 등의 기본 제공 함수를 사용할 수 있습니다.

 

 

@id, @@id

Database상 PRIMARY KEY에 매칭되는 속성입니다.
모든 Prisma Model은 @id 속성을 가진 필드가 존재해야합니다.
@id 속성을 가진 필드는 null이 허용될 수 없습니다.
@@id를 사용하면 다중 필드를 id로 설정할 수 있습니다.

 

 

@unique, @@unique

Database상 UNIQUE에 매칭되는 속성입니다.
모든 Scalar Type에 정의 할 수 있지만, 관계 필드에 정의할 수 없습니다.
unique 제약조건이 설정된 filed는 자동으로 INDEX가 추가됩니다.
@@unique를 사용하면 복합 unique를 설정할 수 있습니다.
(❗@@unique를 설정하는 필드는 모두 null이 허용되지 않아야 합니다.)

 

 

@updatedAt

자동으로 update 된 시간을 저장합니다.

 

autoincrement() , cuid(), uuid(), now()

autoincrement()는 해당 필드를 자동으로 증가하는 값으로 설정합니다.
cuid()는 cuid 사양에 따라 고유한 식별자를 생성합니다.
uuid()는 uuid 사양에 따라 고유한 식별자를 생성합니다.
now()는 생성된 시간의 시간을 기록합니다.

 

 

 

 

 

2.2 Scalar Field

String Boolean Int Float DateTime JSON 의 6개 필드로 구성되어 있습니다.
각각의 필드는 기본적으로 prisma에서 지정한 DB에서의 자료형으로 구성되어 있습니다.

Native Type을 사용하고 싶은 경우, nativeTypes (❗현재 Preview 기능입니다)을 사용할 수 있습니다.

 

 

 

2.3 Relation Field

속성의 @relation을 이용하여 관계를 맺을 수 있습니다.

@relation

Database상 FOREIGN KEY/REFERENCES에 매칭되는 속성입니다.
model상 외래키로 설정 할 필드와, 다른 모델의 PRIMARY KEY를 인수로 가집니다

 

 

@relation(fields: [], references: [])

 

 

 

model User {
  id      Int      @id @default(autoincrement()) ◀️ 값이 자동으로 증가하는 id 필드입니다.
  email   String   @unique ◀️ email은 고유한 값입니다.
  name    String? ◀️ name은 null이 허용됩니다.
  role    Role     @default(USER)  ◀️ 열거형입니다. 기본값은 USER입니다.
  posts   Post[] ◀️ 해당 유저가 작성한 Post 필드입니다. (user:post는 1:n관계입니다.)
  profile Profile? ◀️ profile은 관계필드입니다. null이 허용됩니다. (user:profiled은 1:1관계입니다.)
}
model Profile {
  id      Int     @id @default(autoincrement())
  bio     String
  user    User    @relation(fields: [userId], references: [id]) ◀️ profile에 연결된 user입니다.
  userId  Int 외래키 ◀️(userId)입니다.
}
model Post {
  id         Int         @id @default(autoincrement())
  createdAt  DateTime    @default(now()) ◀️ 현재 시간이 기본값으로 설정됩니다.
  title      String
  published  Boolean     @default(false)
  author     User        @relation(fields: [authorId], references: [id])
  authorId   Int
  categories Category[]  @relation(references: [id])
}
model Category {
  id    Int     @id @default(autoincrement())
  name  String
  posts Post[]  @relation(references: [id])
}
enum Role {
  USER
  ADMIN
}

 

 

 

오늘은 Prisma Model 의 구성과, 예제 Database 를 분석해 보며 Prisma Model 에 대하여 알아보았습니다.
다음 포스트에서는 Prisma를 Node.js 환경에서 사용하는 법에 대하여 알아보겠습니다.

 

 

 

 

 

 

'👩🏻‍💻 TIL' 카테고리의 다른 글

GraphQL  (0) 2022.01.04
쿼리 루트 타입, mutation  (0) 2022.01.01
타입스크립트 자료유형 기초  (0) 2021.12.28
2021_12_26_TIL  (1) 2021.12.26
2021_12_19_TIL  (0) 2021.12.19