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

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

How can i add enum in gorm?

问题

我正在编写 PostgreSQL 表模式。

  1. type TestTable struct {
  2. ID int `gorm:"column:id;primaryKey;autoIncrement"`
  3. CarType string `gorm:"column:car_type"`
  4. }

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

英文:

I am writing PostgreSQL table schema.

  1. type TestTable struct {
  2. ID int `gorm:"column:id;primaryKey;autoIncrement"`
  3. CarType string `gorm:"column:car_type"`
  4. }

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

答案1

得分: 22

假设您正在使用GORM与PostgreSQL。首先,在您的数据库中创建一个类型。

  1. CREATE TYPE car_type AS ENUM (
  2. 'SEDAN',
  3. 'HATCHBACK',
  4. 'MINIVAN'
  5. );

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

  1. import "database/sql/driver"
  2. type carType string
  3. const (
  4. SEDAN carType = "SEDAN"
  5. HATCHBACK carType = "HATCHBACK"
  6. MINIVAN carType = "MINIVAN"
  7. )
  8. func (ct *carType) Scan(value interface{}) error {
  9. *ct = carType(value.([]byte))
  10. return nil
  11. }
  12. func (ct carType) Value() (driver.Value, error) {
  13. return string(ct), nil
  14. }
  15. type MyTable struct {
  16. gorm.Model
  17. CarType carType `gorm:"type:car_type"`
  18. }
  19. func (MyTable) TableName() string {
  20. return "my_table"
  21. }

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

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

或者

  1. 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.

  1. CREATE TYPE car_type AS ENUM (
  2. 'SEDAN',
  3. 'HATCHBACK',
  4. 'MINIVAN');

Then you will need to define the following model:

  1. import "database/sql/driver"
  2. type carType string
  3. const (
  4. SEDAN carType = "SEDAN"
  5. HATCHBACK carType = "HATCHBACK"
  6. MINIVAN carType = "MINIVAN"
  7. )
  8. func (ct *carType) Scan(value interface{}) error {
  9. *ct = carType(value.([]byte))
  10. return nil
  11. }
  12. func (ct carType) Value() (driver.Value, error) {
  13. return string(ct), nil
  14. }
  15. type MyTable struct {
  16. gorm.Model
  17. CarType carType `gorm:"type:car_type"`
  18. }
  19. func (MyTable) TableName() string {
  20. return "my_table"
  21. }

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.

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

OR

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

答案2

得分: 2

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

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

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

  1. type carType string
  2. const (
  3. SEDAN carType = "SEDAN"
  4. HATCHBACK carType = "HATCHBACK"
  5. MINIVAN carType = "MINIVAN"
  6. )
  7. func (self *carType) Scan(value interface{}) error {
  8. *self = carType(value.([]byte))
  9. return nil
  10. }
  11. func (self carType) Value() (driver.Value, error) {
  12. return string(self), nil
  13. }

希望对你有帮助!

英文:

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:

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

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

  1. type carType string
  2. const (
  3. SEDAN carType = "SEDAN"
  4. HATCHBACK carType = "HATCHBACK"
  5. MINIVAN carType = "MINIVAN"
  6. )
  7. func (self *carType) Scan(value interface{}) error {
  8. *self = carType(value.([]byte))
  9. return nil
  10. }
  11. func (self carType) Value() (driver.Value, error) {
  12. return string(self), nil
  13. }

答案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类型:

  1. func (psqlClient *DBClient) CreateCarTypeEnum() error {
  2. result := psqlClient.db.Exec("SELECT 1 FROM pg_type WHERE typname = 'car_type';")
  3. switch {
  4. case result.RowsAffected == 0:
  5. if err := psqlClient.db.Exec("CREATE TYPE car_type AS ENUM ('SEDAN', 'HATCHBACK', 'MINIVAN');").Error; err != nil {
  6. log.Error().Err(err).Msg("Error creating car_type ENUM")
  7. return err
  8. }
  9. return nil
  10. case result.Error != nil:
  11. return result.Error
  12. default:
  13. return nil
  14. }
  15. }
英文:

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:

  1. func (psqlClient *DBClient) CreateCarTypeEnum() error {
  2. result := psqlClient.db.Exec("SELECT 1 FROM pg_type WHERE typname = 'car_type';")
  3. switch {
  4. case result.RowsAffected == 0:
  5. if err := psqlClient.db.Exec("CREATE TYPE car_type AS ENUM ('SEDAN', 'HATCHBACK', 'MINIVAN');").Error; err != nil {
  6. log.Error().Err(err).Msg("Error creating car_type ENUM")
  7. return err
  8. }
  9. return nil
  10. case result.Error != nil:
  11. return result.Error
  12. default:
  13. return nil
  14. }
  15. }

答案5

得分: 1

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

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

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

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

答案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

  1. # task.proto
  2. syntax = "proto3";
  3. enum TaskStatus {
  4. Unknown = 0;
  5. Running = 1;
  6. Exiting = 2;
  7. Pending = 3;
  8. }
  9. # 生成 gorm-serializer.pb.go
  10. protoc --proto_path=. --go_out=paths=source_relative:. --gorm-serializer_out=paths=source_relative:. task.proto
  11. # 使用
  12. type Task struct {
  13. gorm.Model
  14. Name string
  15. Status example.TaskStatus `gorm:"type:int"`
  16. }
英文:

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 .

  1. # task.proto
  2. syntax = "proto3";
  3. enum TaskStatus {
  4. Unknown = 0;
  5. Running = 1;
  6. Exiting = 2;
  7. Pending = 3;
  8. }
  9. # gen gorm-serializer.pb.go
  10. protoc --proto_path=. --go_out=paths=source_relative:. --gorm-serializer_out=paths=source_relative:. task.proto
  11. # use
  12. type Task struct {
  13. gorm.Model
  14. Name string
  15. Status example.TaskStatus `gorm:"type:int"`
  16. }

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:

确定