在gorm中如何添加枚举类型?

huangapple go评论82阅读模式
英文:

How can i add enum in gorm?

问题

我正在编写 PostgreSQL 表模式。

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

那么我该如何将 "SEDAN"、"HATCHBACK"、"MINIVAN" 等车型添加为 enum 数据类型呢?

英文:

I am writing PostgreSQL table schema.

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

So how can i add car types like "SEDAN", "HATCHBACK", "MINIVAN" as enum data type

答案1

得分: 22

假设您正在使用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"`
英文:

Assuming you are using GORM with PostgreSQL. First in your database create a type.

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

Then you will need to define the following model:

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"
}

Note for MySQL users, you can add struct tag gorm: or sql: so you don't have to run raw query to create enum in the database.

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

OR

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

答案2

得分: 2

这里是一个不需要事先创建 SQL 类型的解决方案。你可以使用以下代码来定义你的字段标签:

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

此外,你还需要为 carType 类型添加 ScanValue 方法:

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
}

希望对你有帮助!

英文:

Edit: someone pointed out this only works with MySQL. I would take my answer down but someone using MySQL may find it helpful.

Here's an answer that doesn't require you to create a SQL type beforehand. My source for this solution was this github issue

For your field tag, use this:

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

You'll also need to add the Scan and Value methods attached to your carType type.

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
}

答案3

得分: 1

在这方面,如果你决定采用稍微不同的方法:
你可以将枚举定义为int,并利用iota。然后你可以使用代码生成器来创建SQL的Scaner/Valuer,同时也可以创建JSON/文本表示。
例如:
https://github.com/dmarkham/enumer

英文:

on a side note- if you decide to go with slightly different approach:
you can define your enums as int, and leverage iota. then you can use code generator to create sql Scaner/Valuer but also json/text representations.
for example:
https://github.com/dmarkham/enumer

答案4

得分: 1

为了扩展Nick的答案,我在自动化方面添加了以下内容:

假设你有一个DBClient结构体,你可以创建一个方法来创建这个car类型:

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
	}
}
英文:

in order to extend Nick's answer I am adding the following for automation:

Assuming you have DBClient struct, you can create a method that creates this car type:

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
	}
}

答案5

得分: 1

就像你在SQL中编写的那样,你可以使用类型和添加任何你想要的数据类型,就像你在SQL中编写的那样。

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

Just like you write in sql, you can use type and add whatever datatype you want like you write in sql.

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

答案6

得分: 0

更新,不要使用sql:"car_type",而是使用gorm:"car_type"。而且,你需要手动在数据库中创建自定义的枚举类型。

英文:

An update, it will not work with sql:"car_type" instead use gorm:"car_type". That too once you have manually created the custom enum type into the database.

答案7

得分: -1

https://gorm.io/docs/data_types.html => 实现Scan和Value方法。


如果枚举是由protoc生成的,可以使用这个插件 https://github.com/yangyang5214/protoc-gen-gorm-serializer

# task.proto
syntax = "proto3";

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


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

# 使用
type Task struct {
	gorm.Model
	Name   string
	Status example.TaskStatus `gorm:"type:int"`
}
英文:

https://gorm.io/docs/data_types.html => impl Scan & Value methods.


If enum is generated by protoc, can use this plugin

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"`
}

huangapple
  • 本文由 发表于 2021年8月3日 21:48:30
  • 转载请务必保留本文链接:https://go.coder-hub.com/68637265.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定