Gorm(Postgres)自定义类型主键无法设置自增?

作者站长头像
站长
· 阅读数 9

前提:

  1. gorm.io/gorm v1.25.1
  2. gorm.io/driver/postgres v1.5.0

原因,主键在表自动迁移时无法创建自增。

附代码如下,之所以给主键设置为自定义类型,主要是考虑了bigint在前端可能会丢失精度的问题。现在别的都正常,就是自动创建表时,不会设置为自增。

type GVA_MODEL struct {
  ID BigInt `gorm:"primaryKey;autoIncrement:true;type:bigint;size:64;->" form:"id" json:"id" query:"id"` // 主键ID
  // ...
}
// 自定义类型,让客户端以string形式处理BigInt类型的数据
type BigInt json.Number
// Scan 实现 sql.Scanner 接口,Scan 将 value 扫描至 BigInt
func (bigint *BigInt) Scan(value interface{}) error {
  bytes, ok := value.(int64)
  if !ok {
    return errors.New(fmt.Sprint("Failed to unmarshal Int64 value:", value))
  }

  var result = json.Number(strconv.FormatInt(bytes, 10))
  *bigint = BigInt(result)
  return nil
}

// Value 实现 driver.Valuer 接口,Value 返回 BigInt value
func (bigint BigInt) Value() (driver.Value, error) {
  if len(bigint) == 0 {
    return nil, nil
  }
  return json.Number(bigint).Int64()
}

func (BigInt) GormDBDataType(db *gorm.DB, field *schema.Field) string {
  // 根据不同的数据库驱动返回不同的数据类型
  switch db.Dialector.Name() {
  case "mysql", "sqlite":
    return "bigint"
  case "postgres":
    if field.AutoIncrement { // 这是已修复后的
        return "bigserial"
    }
    return "bigint"
  }
  return "bigint"
}
回复
1个回答
avatar
test
2024-07-03

通过调试 gorm和driver/postgres的代码,已经搞定了,即在GormDBDataType判断字段是否自增,如果是自增,则返回bigserial

func (bigint BigInt) GormDBDataType(db *gorm.DB, field *schema.Field) string {
    // 根据不同的数据库驱动返回不同的数据类型
    switch db.Dialector.Name() {
    case "mysql", "sqlite":
        return "bigint"
    case "postgres":
        if field.AutoIncrement {
            return "bigserial"
        }
        return "bigint"
    }
    return "bigint"
}

PS:如果字段对应类型实现了GormDBDataType接口,则在表创建时,直接以GormDBDataType返回的类型创建表的字段。

回复
likes
适合作为回答的
  • 经过验证的有效解决办法
  • 自己的经验指引,对解决问题有帮助
  • 遵循 Markdown 语法排版,代码语义正确
不该作为回答的
  • 询问内容细节或回复楼层
  • 与题目无关的内容
  • “赞”“顶”“同问”“看手册”“解决了没”等毫无意义的内容