如何在Golang的Gorm中使用UUID?

27

我有以下模型...

type User struct {
    ID        string  `sql:"type:uuid;primary_key;default:uuid_generate_v4()"`
    FirstName string `form:"first_name" json:"first_name,omitempty"`
    LastName  string `form:"last_name" json:"last_name,omitempty"`
    Password  string `form:"password" json:"password" bindind:"required"`
    Email     string `gorm:"type:varchar(110);unique_index" form:"email" json:"email,omitempty" binding:"required"`
    Location  string `form:"location" json:"location,omitempty"`
    Avatar    string `form:"avatar" json:"avatar,omitempty"`
    BgImg     string `form:"bg_img" json:"bg_img,omitempty"`
    CreatedAt time.Time
    UpdatedAt time.Time
    DeletedAt time.Time
}

我尝试了几种不同的方法,但是这种方法会抛出(pq: relation "users" does not exist)的错误。我没有任何相关的模型,只有那个模型。

我尝试使用...

func (user *User) BeforeCreate(scope *gorm.Scope) error {
    scope.SetColumn("ID", uuid.NewV4())
    return nil
}

我尝试使用uuid库,但也没有成功。


似乎您的用户表在数据库中不存在。您是否执行了自动迁移操作? - Apin
现在有更好的方法吗? - jumper
8个回答

17
对于postgresql,我所做的如下:
  • go get github.com/google/uuid
  • 使用uuid.UUID (from "github.com/google/uuid") 作为类型,例如
    ID       uuid.UUID `gorm:"type:uuid;default:uuid_generate_v4()"`
  • 为postgres数据库添加uuid-ossp扩展,例如
    CREATE EXTENSION IF NOT EXISTS "uuid-ossp";
  • 然后,当您调用DB的Create()方法时,uuid会自动生成。

更新:pg14+ gen_random_uuid()

(如Doron Segal的评论中所提到的)

pg 14有内置函数gen_random_uuid()用于生成uuidv4,例如:

创建表:

create table uuid_test (uid text default gen_random_uuid());

插入一行:

insert into uuid_test(uid) values (DEFAULT);

然后,uid列会自动生成。


类似地,在go中,我认为您可以将该函数用作默认值,例如:

ID uuid.UUID gorm:"type:uuid;default:gen_random_uuid()"


顺便说一下gen_random_uuid()函数支持uuidv4,要使用其他版本,仍然需要uuid-ossp扩展。


2
如果您使用的是PostgreSQL版本> 14,则无需使用任何扩展,只需使用gen_random_uuid()即可。 - Doron Segal

13

结果发现我试图把UUID存储为错误的类型,我正在...

func (user *User) BeforeCreate(scope *gorm.Scope) error {
    scope.SetColumn("ID", uuid.NewV4())
    return nil
}

当需要它时...

func (user *User) BeforeCreate(scope *gorm.Scope) error {
    scope.SetColumn("ID", uuid.NewV4().String())
    return nil
}

5
你应该使用return scope.SetColumn("ID", uuid.NewV4().String()),而不是忽略SetColumn的结果。 - Artmann

7

这是我针对Gorm v1.21的解决方案

go get gorm.io/gorm
go get gorm.io/driver/postgres
go get github.com/google/uuid

import (
  "gorm.io/gorm"
  "github.com/google/uuid"
)

type User struct {
  Id string `gorm:"primaryKey"`
}

// Note: Gorm will fail if the function signature
//  does not include `*gorm.DB` and `error`

func (user *User) BeforeCreate(tx *gorm.DB) (err error) {
  // UUID version 4
  user.Id = uuid.NewString()
  return
}

注意:

  1. 对于Google UUID包,方法uuid.New()uuid.NewString()使用UUID版本4。文档中没有明确说明(http://pkg.go.dev/github.com/google/uuid),但通过查看源代码,可以看到这些是围绕uuid.NewRandom()的包装,后者被说明为UUID版本4。

  2. 虽然有人建议使用Satori UUID包(https://github.com/satori/go.uuid),但基准测试表明它的性能比Google UUID包低3.3倍(https://gist.github.com/mattes/69a4ab7027b9e8ee952b5843e7ca6955)。


应该使用 uuid.New(),这样才能正常工作。请更新你的答案。 - HalfWebDev
据我所知,uuid.New()返回的是一个16字节的数组,而不是字符串。如果你有令人信服的理由证明使用uuid.New()uuid.NewString()更好,那么我很乐意更新示例代码。在我看来,uuid.NewString()更好,因为字符串易读,在不同的数据库中也得到了很好的支持。 - tim-montague
嗯,好的。从我尝试过的来看,NewString()uuid 上根本不是一个方法。 - HalfWebDev
@HalfWebDev NewString 方法是在 v1.2.0 版本中添加的(https://pkg.go.dev/github.com/google/uuid#NewString)。使用 go get -u github.com/google/uuid 命令更新包时,是否会包含该方法? - tim-montague
好的,我以为我已经有最新的软件包了,因为我刚刚在上面工作过。结果我使用的是 1.0.0 版本。我会检查是否有最新版本发布。 - HalfWebDev

5

为此,您需要使用 gorm go.uuid

go get github.com/jinzhu/gorm

go get github.com/satori/go.uuid

尝试创建自己的基础模型代替gorm.Model,步骤如下:
type Base struct {
 ID         string     `sql:"type:uuid;primary_key;default:uuid_generate_v4()"`
 CreatedAt  time.Time  `json:"created_at"`
 UpdatedAt  time.Time  `json:"updated_at"`
 DeletedAt  *time.Time `sql:"index" json:"deleted_at"`
}

您可以使用一个称为“在创建任何记录之前”的方法来填充此字段,如下所示:
func (base *Base) BeforeCreate(scope *gorm.Scope) error {
 id, err := uuid.NewV4()
 if err != nil {
   return err
 }
 return scope.SetColumn("ID", uuid.String())
}

因此,针对您的特定情况,您将具有:
type User struct {
    Base
    FirstName string `form:"first_name" json:"first_name,omitempty"`
    LastName  string `form:"last_name" json:"last_name,omitempty"`
    Password  string `form:"password" json:"password" bindind:"required"`
    Email     string `gorm:"type:varchar(110);unique_index" form:"email" json:"email,omitempty" binding:"required"`
    Location  string `form:"location" json:"location,omitempty"`
    Avatar    string `form:"avatar" json:"avatar,omitempty"`
    BgImg     string `form:"bg_img" json:"bg_img,omitempty"`
}

更多详细信息可以在这里找到。


14
default:uuid_generate_v4() 会自动生成一个 UUID,对吗? - Carlos Martinez
这段代码肯定会返回一个错误 uuid, err := uuid.NewV4().String() - stelios
1
在这一行中加入.String()return scope.SetColumn("ID", uuid.String()) - Tor
这在写作时是有效的。我没有跟进它,也没有在我的当前职责中积极使用Go,但我会进行所请求的更改。 - Peter Mghendi

1
错误信息 (pq: relation "users" does not exist) 通常意味着,数据库中不存在表格 users。这与两个模型之间的关系无关。因此,您需要首先在数据库中创建该表格(或按照 @Apin 的建议自动迁移数据库),然后尝试重新运行相同的代码。

0
现在我使用了 Gorm 2.0,这个方法有效:
go get github.com/satori/go.uuid 

type Tablename struct {
 ID         string     `sql:"type:uuid;primary_key;default:uuid_generate_v4()"`
 }

0

使用 gorm v1.21,这些都对我没用。

这是我的解决方案。请注意,我使用 satori/go.uuid 库生成 UUID,但使用 Google 的库的代码几乎相同。

type UUIDBaseModel struct {
    ID        uuid.UUID       `gorm:"primary_key" json:"id"`
    CreatedAt time.Time  `json:"created_at"`
    UpdatedAt time.Time  `json:"updated_at"`
    DeletedAt *time.Time `sql:"index" json:"deleted_at"`
}

func (base *UUIDBaseModel) BeforeCreate(tx *gorm.DB) error {
    uuid := uuid.NewV4().String()
    tx.Statement.SetColumn("ID", uuid)
    return nil
}

0

使用MySQL 8.0和gorm(gorm.io/driver/mysql v1.5.0和gorm.io/gorm v1.25.1):

type ModelUUID struct {
    ID        string         `gorm:"type:binary(16);column:id;primaryKey;default:(UUID_TO_BIN(UUID(), 1));" json:"id" validate:"required"`
    CreatedAt time.Time      `json:"createdAt"`
    UpdatedAt time.Time      `json:"-"`
    DeletedAt gorm.DeletedAt `json:"-" gorm:"index" swaggerignore:"true"`
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接