如何在gorm中添加枚举?

ffvjumwh  于 2023-09-28  发布在  Go
关注(0)|答案(7)|浏览(137)

我正在写PostgreSQL表模式。

type TestTable struct {
    ID        int    `gorm:"column:id;primaryKey;autoIncrement"`
    CarType   string `gorm:"column:car_type"`
}

那么,我如何添加汽车类型,如“SEDAN”,“HATCHBACK”,“MINIVAN”作为enum数据类型

jv4diomz

jv4diomz1#

假设你使用的是GORM和PostgreSQL。首先在数据库中创建一个类型。

CREATE TYPE car_type AS ENUM (
    'SEDAN',
    'HATCHBACK',
    'MINIVAN');

然后,您需要定义以下模型:

import "database/sql/driver"

type carType string

const (
    SEDAN  carType = "SEDAN"
    HATCHBACK carType = "HATCHBACK"
    MINIVAN carType = "MINIVAN"
)

func (ct *carType) Scan(value interface{}) error {
    *ct = carType(value.([]byte))
    return nil
}

func (ct carType) Value() (driver.Value, error) {
    return string(ct), nil
}

type MyTable struct {
    gorm.Model
    CarType carType `gorm:"type:car_type"`
}

func (MyTable) TableName() string {
    return "my_table"
}

对于MySQL用户,您可以添加结构标记gorm:sql:,这样您就不必运行原始查询来在数据库中创建枚举。

CarType carType `gorm:"type:enum('SEDAN', 'HATCHBACK', 'MINIVAN')";"column:car_type"`

CarType carType `sql:"type:ENUM('SEDAN', 'HATCHBACK', 'MINIVAN')" gorm:"column:car_type"`
nszi6y05

nszi6y052#

编辑:有人指出这只适用于MySQL。我会把我的答案写下来,但使用MySQL的人可能会发现它很有帮助。
这里有一个不需要您事先创建SQL类型的答案。这个解决方案的来源是这个github issue
对于字段标记,请使用以下命令:

type TestTable struct {
    ID        int     `gorm:"column:id;primaryKey;autoIncrement"`
    CarType   carType `sql:"type:ENUM('SEDAN', 'HATCHBACK', 'MINIVAN')" gorm:"column:car_type"`
}

您还需要添加附加到carType类型的Scan和Value方法。

type carType string

const (
    SEDAN carType = "SEDAN"
    HATCHBACK carType = "HATCHBACK"
    MINIVAN carType = "MINIVAN"
)

func (self *carType) Scan(value interface{}) error {
    *self = carType(value.([]byte))
    return nil
}

func (self carType) Value() (driver.Value, error) {
    return string(self), nil
}
b4qexyjb

b4qexyjb3#

顺便说一句-如果你决定用稍微不同的方法:你可以将你的枚举定义为int,并利用iota。然后你可以使用代码生成器来创建sql Scaner/Valuer,也可以创建json/text表示。例如:https://github.com/dmarkham/enumer

68bkxrlz

68bkxrlz4#

为了扩展Nick的答案,我为自动化添加以下内容:
假设你有DBClient结构体,你可以创建一个方法来创建这个汽车类型:

func (psqlClient *DBClient) CreateCarTypeEnum() error {
    result := psqlClient.db.Exec("SELECT 1 FROM pg_type WHERE typname = 'car_type';")

    switch {
    case result.RowsAffected == 0:
        if err := psqlClient.db.Exec("CREATE TYPE car_type AS ENUM ('SEDAN', 'HATCHBACK', 'MINIVAN');").Error; err != nil {
            log.Error().Err(err).Msg("Error creating car_type ENUM")
            return err
        }

        return nil
    case result.Error != nil:
        return result.Error

    default:
        return nil
    }
}
5m1hhzi4

5m1hhzi45#

就像你写在SQL中,你可以使用类型,并添加任何数据类型,你想像你写在SQL中。

type MyTable struct {
    CarType    string `gorm:"column:car_type;type:enum('SEDAN','HATCHBACK','MINIVAN')" json:"car_type"`
}
u2nhd7ah

u2nhd7ah6#

一个更新,它将不与sql:"car_type"工作,而是使用gorm:"car_type"。在数据库中手动创建自定义枚举类型后,也是如此。

mutmk8jj

mutmk8jj7#

https://gorm.io/docs/data_types.html => impl Scan & Value方法。
如果enum是由protoc生成的,可以使用这个插件
https://github.com/yangyang5214/protoc-gen-gorm-serializer

# task.proto
syntax = "proto3";

enum TaskStatus {
  Unknown = 0;
  Running = 1;
  Exiting = 2;
  Pending = 3;
}

# gen gorm-serializer.pb.go
protoc --proto_path=.  --go_out=paths=source_relative:. --gorm-serializer_out=paths=source_relative:.  task.proto

# use 
type Task struct {
    gorm.Model
    Name   string
    Status example.TaskStatus `gorm:"type:int"`
}

相关问题