GORM 사용자 정의 Gorm. Model 시간 스탬프 자동 추가

잔말 말고 바로 시작 해.
홈 페이지http://gorm.io) 기본 gorm. Model 모델 이 있 습 니 다. 정 의 는 다음 과 같 습 니 다.
package gorm

import "time"

// Model base model definition, including fields `ID`, `CreatedAt`, `UpdatedAt`, `DeletedAt`, which could be embedded in your models
//    type User struct {
//      gorm.Model
//    }
type Model struct {
    ID        uint `gorm:"primary_key"`
    CreatedAt time.Time
    UpdatedAt time.Time
    DeletedAt *time.Time `sql:"index"`
}

네 개의 속성, ID, 생 성 시간, 업데이트 시간, 삭제 시간 을 포함 하 며, 데 이 터 를 조작 할 때 해당 시간 이 자동 으로 변경 되 며, 삭제 시 삭 제 를 소프트 삭제 로 변경 하고 삭제 시간 을 추가 합 니 다.
왜 홈 페이지 에 이미 있 는데 도 스스로 한 벌 써 야 합 니까?이 유 는 세 가지 가 있다.
1. 제 가 하 는 일 은 프로젝트 재 구성 입 니 다. 기 존의 데이터베이스 에 GUID 형식의 메 인 키 가 있 는데 이 모델 과 충돌 합 니 다. (왠 지 모 르 겠 지만 공식 적 으로 복합 메 인 키 를 지원 한다 고 명 확 히 밝 혔 지만 이렇게 하 는 것 을 권장 하지 않 습 니 다)
2. 세 개의 시간 필드 는 시간 을 저장 하고 원래 프로젝트 에 저 장 된 시간 스탬프 입 니 다.
3. 엄 살
재 작성 을 결정 한 이상 그 가 어떻게 작 동 하 는 지 먼저 알 아야 한다. 소스 코드 에서 DB 대상 을 찾 는 정 의 는 다음 과 같다.
db    ,       value,      product{}
type DB struct {
    Value        interface{}
    Error        error
    RowsAffected int64

    // single db
    db                SQLCommon //  db.sql  ,  query       
    blockGlobalUpdate bool
    logMode           int
    logger            logger
    search            *search //       where, limit, group,    db.clone() ,   search
    values            map[string]interface{}

    // global db
    parent        *DB
    callbacks     *Callback //  sql        
    dialect       Dialect //         sql.db
    singularTable bool
}

//     sql      
type Scope struct {
    Search          *search //     
    Value           interface{}
    SQL             string //sql
    SQLVars         []interface{}
    db              *DB //sql.db
    instanceID      string
    primaryKeyField *Field
    skipLeft        bool
    fields          *[]*Field //  
    selectAttrs     *[]string
}

//               ,  create  ,    creates        
type Callback struct {
    creates    []*func(scope *Scope)
    updates    []*func(scope *Scope)
    deletes    []*func(scope *Scope)
    queries    []*func(scope *Scope)
    rowQueries []*func(scope *Scope)
    processors []*CallbackProcessor
}

코드 참조: https://blog.csdn.net/qq_17612199/article/details/79437795
(공식 소스 코드 에 주석 이 없습니다)
자, 이제 알 겠 습 니 다.
// Define callbacks for creating
func init() {
    DefaultCallback.Create().Register("gorm:begin_transaction", beginTransactionCallback)
    DefaultCallback.Create().Register("gorm:before_create", beforeCreateCallback)
    DefaultCallback.Create().Register("gorm:save_before_associations", saveBeforeAssociationsCallback)
    DefaultCallback.Create().Register("gorm:update_time_stamp", updateTimeStampForCreateCallback)
    DefaultCallback.Create().Register("gorm:create", createCallback)
    DefaultCallback.Create().Register("gorm:force_reload_after_create", forceReloadAfterCreateCallback)
    DefaultCallback.Create().Register("gorm:save_after_associations", saveAfterAssociationsCallback)
    DefaultCallback.Create().Register("gorm:after_create", afterCreateCallback)
    DefaultCallback.Create().Register("gorm:commit_or_rollback_transaction", commitOrRollbackTransactionCallback)
}

'update 찾기time_stamp '대응 하 는 방법' updateTimeStampForCreateCallback '
// updateTimeStampForCreateCallback will set `CreatedAt`, `UpdatedAt` when creating
func updateTimeStampForCreateCallback(scope *Scope) {
    if !scope.HasError() {
        now := NowFunc()

        if createdAtField, ok := scope.FieldByName("CreatedAt"); ok {
            if createdAtField.IsBlank {
                createdAtField.Set(now)
            }
        }

        if updatedAtField, ok := scope.FieldByName("UpdatedAt"); ok {
            if updatedAtField.IsBlank {
                updatedAtField.Set(now)
            }
        }
    }
}

// NowFunc returns current time, this function is exported in order to be able
// to give the flexibility to the developer to customize it according to their
// needs, e.g:
// gorm.NowFunc = func() time.Time {
// return time.Now().UTC()
// }
var NowFunc = func() time.Time {
    return time.Now()
}
 

자, 이 단계 에 이 르 러 서 는 여러분 이 어떻게 다시 써 야 할 지 이미 알 고 있다 고 믿 습 니 다. 주의해 야 할 것 은 위의 Default Callback. Create () 가 사용 하 는 것 은 Register () 방법 입 니 다. Create () 의 정 의 는 다음 과 같 습 니 다.
// Register a new callback, refer `Callbacks.Create`
func (cp *CallbackProcessor) Register(callbackName string, callback func(scope *Scope)) {
    if cp.kind == "row_query" {
        if cp.before == "" && cp.after == "" && callbackName != "gorm:row_query" {
            log.Printf("Registing RowQuery callback %v without specify order with Before(), After(), applying Before('gorm:row_query') by default for compatibility...
", callbackName) cp.before = "gorm:row_query" } } cp.name = callbackName cp.processor = &callback cp.parent.processors = append(cp.parent.processors, cp) cp.parent.reorder() }

이미 등록 을 했 으 니 다시 쓰 면 Register 를 사용 할 수 없습니다. 원본 코드 에서 원래 의 리 셋 을 바 꾸 는 방법 을 찾 았 습 니 다. 그 정 의 는 다음 과 같 습 니 다.
// Replace a registered callback with new callback
//     db.Callback().Create().Replace("gorm:update_time_stamp_when_create", func(*Scope) {
//           scope.SetColumn("Created", now)
//           scope.SetColumn("Updated", now)
//     })
func (cp *CallbackProcessor) Replace(callbackName string, callback func(scope *Scope)) {
    log.Printf("[info] replacing callback `%v` from %v
", callbackName, fileWithLineNum()) cp.name = callbackName cp.processor = &callback cp.replace = true cp.parent.processors = append(cp.parent.processors, cp) cp.parent.reorder() }

자, 파악 할 것 은 다 파악 하 였 으 니 지금부터 실제로 해 보 자.
프로젝트 에서 model 폴 더 는 맵 데이터베이스 모델 을 저장 하고 changemol. go 파일 을 새로 만 드 는 데 사 용 됩 니 다.
package model

type ChangeModel struct{
    CreatedTime int32 
    UpdatedTime int32
    DeletedTime int32
}

이벤트 기록 이 필요 한 모델 에 ChangeModel 을 도입 합 니 다.
package model

//User
type User struct{
    ChangeModel
    UserID string `gorm:"primary_key;size:36"`
    Name string `gorm:"size:20"`
    PassWord string `gorm:"size:40"`
}

자, 여기까지 사용자 정의 공공 필드 가 완료 되 었 습 니 다. 다음은 가장 중요 한 리 셋 과 주입 입 니 다.
데이터베이스 연결 파일 열기
package mysqltools

import (
    "fmt"
    "github.com/jinzhu/gorm"
    _ "github.com/jinzhu/gorm/dialects/mysql"
    "log"
    "sync"
    "time"
)

type MysqlConnectiPool struct {
}

var instance *MysqlConnectiPool
var once sync.Once

var db *gorm.DB
var err_db error

func GetInstance() *MysqlConnectiPool {
    once.Do(func() {
        instance = &MysqlConnectiPool{}
    })
    return instance
}

/*
* @fuc         (  mail()      )
*/
func (m *MysqlConnectiPool) InitDataPool() (issucc bool) {
    db, err_db = gorm.Open("mysql", "name:password@tcp(127.0.0.1:3306)/test?charset=utf8&parseTime=True&loc=Local")
    fmt.Println(err_db)
    if err_db != nil {
        log.Fatal(err_db)
        return false
    }
    db.DB().SetMaxIdleConns(10)
    db.DB().SetMaxOpenConns(100)
    db.DB().SetConnMaxLifetime(time.Hour)
    db.Callback().Create().Replace("gorm:update_time_stamp",updateTimeStampForCreateCallback)
    db.Callback().Update().Replace("gorm:update_time_stamp",updateTimeStampForUpdateCallback)
    db.Callback().Delete().Replace("gorm:delete", deleteCallback)
    return true
}
func (m *MysqlConnectiPool) GetMysqlDB() (db_con *gorm.DB) {
    return db
}


// //             
func updateTimeStampForCreateCallback(scope *gorm.Scope) {
   
    if !scope.HasError() {
        nowTime := time.Now().Unix()
        if createTimeField, ok := scope.FieldByName("CreatedTime"); ok {
            if createTimeField.IsBlank {
                createTimeField.Set(nowTime)
            }
        }

        if modifyTimeField, ok := scope.FieldByName("UpdatedTime"); ok {
            if modifyTimeField.IsBlank {
                modifyTimeField.Set(nowTime)
            }
        }
    }
}
//             
func updateTimeStampForUpdateCallback(scope *gorm.Scope) {
    if _, ok := scope.Get("gorm:update_column"); !ok {
        scope.SetColumn("UpdatedTime", time.Now().Unix())
    }
}
//            
func deleteCallback(scope *gorm.Scope) {
    if !scope.HasError() {
        var extraOption string
        if str, ok := scope.Get("gorm:delete_option"); ok {
            extraOption = fmt.Sprint(str)
        }

        deletedOnField, hasDeletedOnField := scope.FieldByName("DeletedTime")

        if !scope.Search.Unscoped && hasDeletedOnField {
            scope.Raw(fmt.Sprintf(
                "UPDATE %v SET %v=%v%v%v",
                scope.QuotedTableName(),
                scope.Quote(deletedOnField.DBName),
                scope.AddToVars(time.Now().Unix()),
                addExtraSpaceIfExist(scope.CombinedConditionSql()),
                addExtraSpaceIfExist(extraOption),
            )).Exec()
        } else {
            scope.Raw(fmt.Sprintf(
                "DELETE FROM %v%v%v",
                scope.QuotedTableName(),
                addExtraSpaceIfExist(scope.CombinedConditionSql()),
                addExtraSpaceIfExist(extraOption),
            )).Exec()
        }
    }
}
func addExtraSpaceIfExist(str string) string {
    if str != "" {
        return " " + str
    }
    return ""
}

세 개의 대응 하 는 리 셋 을 볼 수 있 습 니 다.
    db.Callback().Create().Replace("gorm:update_time_stamp",updateTimeStampForCreateCallback)
    db.Callback().Update().Replace("gorm:update_time_stamp",updateTimeStampForUpdateCallback)
    db.Callback().Delete().Replace("gorm:delete", deleteCallback)

주의 하 다.
갈 고 리 는 만능 이 아니다. Raw () 를 사용 하여 원생 SQL 을 쓸 때 갈 고 리 는 효력 을 잃 고 대량 조작 은 갈 고 리 를 무효 로 할 수 있다. 또 다른 특수 한 방법 도 있 기 때문에 중요 한 데 이 터 는 절대 게 으 름 피 우지 말고 갈고리 로 조작 해 야 한다.
다음으로 전송:https://www.cnblogs.com/sgyBlog/p/10154424.html

좋은 웹페이지 즐겨찾기