gorm 구조체 필드 default 태그 유의사항

// gorm 으로 다음과 같이 test_info 테이블에 들어가는 구조체를 만들고
type TestInfo struct {
  ID       int64
  LastDate time.Time
  Age      int    `gorm:"default:99"`
  Name     string `gorm:"default:lemon"`
  Enable   bool   `gorm:"not null;default:1"`
}

// 해당 레코드를 삭제 후 Save() 로 저장하면
// 아래 설정된 값이 아닌 default 값이 설정돼
// Name = lemon, Age = 99, Enable = true 값으로 저장된다.
db.Delete(TestInfo{}, "id = ?", user.ID)
user.Name = ""
user.Age = 0
user.Enable = false
db.Save(&user)

// 원인 파악 및 해결방법
// Save() 는 update 후 select 로 레코드를 확인하는데
// Delete() 로 해당 레코드가 없으면 insert(gorm create함수)를 수행한다.
// 이때 만약 구조체 필드 중 `gorm:"default:xxx"` 값이 설정되어 있고
// 그 필드가 초기값 bool = false, int = 0, string = "" 등인 경우
// Save() -> Create() -> Execute() -> f() ->
// callbacks/create.go Create() ->
// ConvertToCreateValues() -> case reflect.Struct ->
// isZero() 로 해당 필드가 값이 설정되지 않은 것으로 판단해
// 다음과 같이 default 값으로 insert 구문을 생성해 실행한다.
// INSERT INTO `test_info` (`age`,`name`,`last_date`,`enable`,`id`) VALUES (99,'lemon','2020-10-20 23:37:54',true,89)

// 만약 bool = false, int = 0, string = "" 인 상태로 저장하고 싶다면
// default:xxx 태그를 명시하면 안된다.
// 사실 Name="", Age=0, Enable=false 자체가 값을 설정한것이지만 
// gorm 에서는 go reflect IsZero() 로 타입별 값 설정이 안되었다고 판단한다.
// IsZero 는 값 존재가 아니라 그 타입의 값이 0(false)인지를 파악한다.
// 테스트 코드

#####

// gorm 버전업에 따른 repo 및 연결/초기 설정 api 변경사항
// gorm v1.9.16 이전 방식
import github.com/jinzhu/gorm v1.9.13
db, err := gorm.Open("mysql", DSN)

// 테이블명이 a_b_xxs 처럼 복수형 이름을 사용하지 않게 설정
db.SingularTable(true)

// 수행한 쿼리 stdout 출력
db.LogMode(true)

// gorm v1.9.16 이후 방식
import gorm.io/driver/mysql v1.0.2
import gorm.io/gorm v1.20.2

db, err := gorm.Open(mysql.Open(DSN), 
    &gorm.Config{
        NamingStrategy: schema.NamingStrategy{SingularTable: true},
        Logger: logger.Default.LogMode(logger.Info)
})

comments:

댓글 쓰기