如何防止 gorm 将自定义整数类型转换为字符串?
How to prevent gorm from converting custom integer types into strings?
我在将 gorm 与具有整数属性的自定义类型一起使用时遇到了问题。 Gorm 倾向于为我将整数值转换为字符串。有两个不同的问题:
问题一:
我有一个自定义类型定义如下:
type ClientType uint8
const (
USER ClientType = iota
SERVER
)
func (t ClientType) String() string {
return [...]string{"User", "Service"}[t]
然后我为 Client
定义了一个 ORM 结构,如下所示:
type Client struct {
ClientID uint64 `gorm:"primaryKey"`
UserID uint64
ClientType ClientType
CreatedAt time.Time
}
当调用db.Create(&client)
时,gorm自动调用了ClientType
上的String()
方法,导致我打算存储[=15]的MySQL中的数据类型不匹配=] 在名为 client_type
.
的 TINYINT
列中
问题二:
所以我想,如果我想不出如何覆盖String()
方法的自动调用,我只是将方法重命名为ToString()
并在需要时调用它。现在 gorm 不能再调用它,而是将整数值转换为数字字符串。因此 USER
即 0
,现在将在结果 SQL 语句中变为 '0'
,而 SERVER
将变为 '1'
,尽管 [=56] =] 能够将字符串转换回整数。
我仍然想知道我做错了什么让 gorm 认为我想要这些转换。
- 有没有办法覆盖
String()
的调用,这样我仍然可以约定俗成的方法命名?
- 是否使用
uint8
让 gorm 将 int 转换为字符串,因为使用 uint64 的其他数值(ClientID 和 UserID)不受此问题的影响?是不是数据库模式的某种缓存让 gorm 记住了 client_type 曾经是 ENUM('User', 'Service')
列的旧模式?
根据自定义类型的 gorm Value and Scan 需要实施。
您也可以尝试在结构中指定类型(将 替换为列类型)。
type Client struct {
ClientID uint64 `gorm:"primaryKey"`
UserID uint8
ClientType ClientType `gorm:"type:<TYPE>"`
CreatedAt time.Time
}
String() 似乎不是问题,因为它不会在创建期间调用,而只会在查找期间调用。
使用 db.LogMode(true)
,它也在创建期间调用,但这似乎是为了 sql 查询日志记录而不是为了发送到数据库。
关闭日志模式
db.LogMode(false)
fmt.Println("Creating")
db.Create(&Client{ClientID: 9, UserID: 8, ClientType: USER, CreatedAt: time.Now()})
fmt.Println("Created")
fmt.Println("Finding")
db.First(&client)
fmt.Printf("Found %v\n", client)
输出
Creating
Created
Finding
String() called with 0
Found {9 8 User 2021-01-28 11:41:51.355633057 +0530 +0530}
开启日志模式
db.LogMode(true)
fmt.Println("Creating")
db.Create(&Client{ClientID: 9, UserID: 8, ClientType: USER, CreatedAt: time.Now()})
fmt.Println("Created")
fmt.Println("Finding")
db.First(&client)
fmt.Printf("Found %v\n", client)
输出:
Creating
String() called with 0
[2021-01-28 11:39:30] [0.95ms] INSERT INTO "clients" ("client_id","user_id","client_type","created_at") VALUES (9,8,'User','2021-01-28 11:39:30')
[1 rows affected or returned ]
Created
Finding
[2021-01-28 11:39:30] [1.49ms] SELECT * FROM "clients" LIMIT 1
[1 rows affected or returned ]
String() called with 0
Found {9 8 User 2021-01-28 11:42:31.245628274 +0530 +0530}
我在将 gorm 与具有整数属性的自定义类型一起使用时遇到了问题。 Gorm 倾向于为我将整数值转换为字符串。有两个不同的问题:
问题一:
我有一个自定义类型定义如下:
type ClientType uint8
const (
USER ClientType = iota
SERVER
)
func (t ClientType) String() string {
return [...]string{"User", "Service"}[t]
然后我为 Client
定义了一个 ORM 结构,如下所示:
type Client struct {
ClientID uint64 `gorm:"primaryKey"`
UserID uint64
ClientType ClientType
CreatedAt time.Time
}
当调用db.Create(&client)
时,gorm自动调用了ClientType
上的String()
方法,导致我打算存储[=15]的MySQL中的数据类型不匹配=] 在名为 client_type
.
TINYINT
列中
问题二:
所以我想,如果我想不出如何覆盖String()
方法的自动调用,我只是将方法重命名为ToString()
并在需要时调用它。现在 gorm 不能再调用它,而是将整数值转换为数字字符串。因此 USER
即 0
,现在将在结果 SQL 语句中变为 '0'
,而 SERVER
将变为 '1'
,尽管 [=56] =] 能够将字符串转换回整数。
我仍然想知道我做错了什么让 gorm 认为我想要这些转换。
- 有没有办法覆盖
String()
的调用,这样我仍然可以约定俗成的方法命名? - 是否使用
uint8
让 gorm 将 int 转换为字符串,因为使用 uint64 的其他数值(ClientID 和 UserID)不受此问题的影响?是不是数据库模式的某种缓存让 gorm 记住了 client_type 曾经是ENUM('User', 'Service')
列的旧模式?
根据自定义类型的 gorm Value and Scan 需要实施。
您也可以尝试在结构中指定类型(将
type Client struct {
ClientID uint64 `gorm:"primaryKey"`
UserID uint8
ClientType ClientType `gorm:"type:<TYPE>"`
CreatedAt time.Time
}
String() 似乎不是问题,因为它不会在创建期间调用,而只会在查找期间调用。
使用 db.LogMode(true)
,它也在创建期间调用,但这似乎是为了 sql 查询日志记录而不是为了发送到数据库。
关闭日志模式
db.LogMode(false)
fmt.Println("Creating")
db.Create(&Client{ClientID: 9, UserID: 8, ClientType: USER, CreatedAt: time.Now()})
fmt.Println("Created")
fmt.Println("Finding")
db.First(&client)
fmt.Printf("Found %v\n", client)
输出
Creating
Created
Finding
String() called with 0
Found {9 8 User 2021-01-28 11:41:51.355633057 +0530 +0530}
开启日志模式
db.LogMode(true)
fmt.Println("Creating")
db.Create(&Client{ClientID: 9, UserID: 8, ClientType: USER, CreatedAt: time.Now()})
fmt.Println("Created")
fmt.Println("Finding")
db.First(&client)
fmt.Printf("Found %v\n", client)
输出:
Creating
String() called with 0
[2021-01-28 11:39:30] [0.95ms] INSERT INTO "clients" ("client_id","user_id","client_type","created_at") VALUES (9,8,'User','2021-01-28 11:39:30')
[1 rows affected or returned ]
Created
Finding
[2021-01-28 11:39:30] [1.49ms] SELECT * FROM "clients" LIMIT 1
[1 rows affected or returned ]
String() called with 0
Found {9 8 User 2021-01-28 11:42:31.245628274 +0530 +0530}