공부하고 기록하는, 경제학과 출신 개발자의 노트

학습일지/데이터베이스

간단하게 GORM 다루어보기

inspirit941 2021. 12. 6. 21:34
반응형

https://www.youtube.com/watch?v=9koLNdEcSR0

위 영상에서 다룬 내용들을 정리했음.

2020년 8월 기준 영상이라, 영상 이후 변경 혹은 수정된 방식의 GORM 사용법으로 업데이트했다.

GORM

  • Code-first ORM.
  • go code로 Create DB Schema, interact with DB with Writing SQL Query 등을 가능하게 함.

https://gorm.io/docs/models.html

package main

import (
    "fmt"
    "log"

    "gorm.io/gorm"
    "gorm.io/driver/sqlite"
)
/* 
테이블 정의하기

- gorm.Model을 struct의 정의부에 추가한다.
- primary Key인 ID, createdAt, UpdatedAt DeletedAt이 정의되어 있음.
  - ID는 어떤 데이터 타입이든 상관없다. struct에 ID 필드가 정의되어 있다면 그걸 자동으로 primary key로 사용함.

*/
type Channel struct {
    gorm.Model
    Name        string
    Description string
}

type User struct {
    gorm.Model
    Email    string
    Username string
}

// https://gorm.io/docs/belongs_to.html

type Message struct {
    gorm.Model
    Content   string
    UserID    int // foreign key 자동인식. UserID를 반드시 입력해줘야 Belongs to 관계가 성립된다.
    User      User
    ChannelID int
    Channel   Channel
}

// https://gorm.io/docs/migration.html
/*
기본적으로 migrate는 자동.
- only creates table, missing columns and missing indexes. (이미 정의된 것을 변경하거나 삭제하지는 않는다.)
*/
// create 3 table in DB.
func setup(db *gorm.DB) {
    db.AutoMigrate(&Channel{}, &User{}, &Message{})
    seed(db)
}

func seed(db *gorm.DB) {
    channels := []Channel{
        {Name: "General", Description: "General Discussions"},
        {Name: "Off-Topic", Description: "Weird stuff goes here"},
        {Name: "Suggestions", Description: "Video suggestions go here"},
    }

    // https://gorm.io/docs/create.html
    // Batch insert 기능. slice를 파라미터로 넣으면 된다.
    db.Create(&channels)


    users := []User{
        {Email: "test@test.com", Username: "Joe420"},
        {Email: "yes@yes.com", Username: "Bob"},
    }

    db.Create(&users)


    var generalChat, suggestionsChat Channel

    // https://gorm.io/docs/query.html
    // 조건문 걸어서 field 조회하는 방법.
    db.Where("Name = ?", "General").First(&generalChat)

    // inline Condition 형태로도 사용 가능.
    db.First(&suggestionsChat, "Name = ?", "Suggestions")
    var joe, bob User
    db.First(&joe, "Username = ?", "Joe420")
    db.First(&bob, "Username = ?", "Bob")

    // 사용자 정의 struct가 포함되어 있는 경우 (generalChat과 job이라는 struct 사용 시)
    // -> DB 조회해서 있으면 그거 연결하고, 없으면 생성한다.
    messages := []Message{
        {Content: "Hello!", Channel: generalChat, User: joe},
        {Content: "What up", Channel: generalChat, User: bob},
        {Content: "Make more go videos", Channel: suggestionsChat, User: joe},
    }

    db.Create(&messages)    
}

func main() {
    // Logger 세팅: https://gorm.io/docs/logger.html
    newLogger := logger.New(
    log.New(os.Stdout, "\r\n", log.LstdFlags), // io writer
        logger.Config{
            SlowThreshold:              time.Second,   // Slow SQL threshold
            LogLevel:                   logger.Silent, // Log level
            IgnoreRecordNotFoundError: true,           // Ignore ErrRecordNotFound error for logger
            Colorful:                  false,          // Disable color
        },
    )

    // sqlite3 사용. 어떤 db를 쓰느냐에 따라 다르게 정의해서 쓰면 됨
    db, err := gorm.Open(sqlite.Open("test.db"), &gorm.Config{
        Logger : newLogger,
    })
    if err != nil {
        panic("can't connect to database")
    }
    defer os.Remove("test.db")

    setup(db)

    var users []User

    db.Find(&users) // select all users


    for i, u := range users {
        fmt.Println(i)
        fmt.Println("Email:", u.Email, "Username:", u.Username)
    }
    var messages []Message


    //  https://gorm.io/docs/preload.html
    //db.Preload("User").Find(&messages) -> Eager loading 기능.
    //db.Model(users[0]).Related(&message) -> 현재는 Related 메소드는 지원하고 있지 않음.
    db.Preload("User").Find(&messages, &Message{UserID: users[0].ID})

    for _, m := range messages {
        fmt.Println("Message:", m.Content, "Sender:", m.User.Email)
    }
    doError(db)
}

func doError(db *gorm.DB) {
    var fred User
    // Error handling.
    if err := db.Where("username = ?", "Fred").First(&fred).Error; err != nil {
        log.Fatalf("Error when loading user: %s", err)
    }
}

특징

  • gorm.Model 세팅할 때 deletedAt 필드가 있으면 자동으로 soft delete가 적용된다. deletedAt 필드에 delete 요청한 시간이 기록되며, normal Query로는 해당 row를 더 이상 찾을 수 없게 된다.
  • 그래서 deletedAt에는 자동으로 index가 생성된다.

 

반응형