英文:
Setting UUID field to NULL with gorm
问题
我正在使用的数据库是PostgreSQL,ORM是gorm。我有一个包含assigned_id
字段的数据库表,该字段的类型是uuid
。
我想知道如何将assigned_id
设置为NULL
。
我尝试在模型中将该字段设置为nil,还尝试使用gorm.Expr("NULL")
、nil
或sql.NullString
,但这些方法都不起作用。
也许有人能够回答我的问题。
英文:
I'm having a database table which contains a assigned_id
field which has the type uuid
.
The database is postgres and my ORM is gorm. I was wondering how its possible to set that assigned_id
to NULL
?
I've tried setting the field to nil in the model, as well as using gorm.Expr("NULL")
, nil
or sql.NullString
.
None of those methods work.
Maybe someone will be able to answer that question for me.
答案1
得分: 3
你可以声明一个自定义类型来处理uuid(或任何其他非默认类型)。我已经提供了实现,并且通过了我的测试示例。注意:我已经声明了一个自定义类型来处理空字符串,但为了简洁起见,我将其省略了。
此外,我没有对这段代码进行完整的测试覆盖,所以请将其作为一个起点。
type NullUUID struct {
UUID uuid.UUID
Valid bool
}
func (nd *NullUUID) Scan(value interface{}) (err error) {
var s uuid.UUID
if err := s.Scan(value); err != nil {
return err
}
// 如果为空,则将Valid设置为false
if reflect.TypeOf(value) == nil {
*nd = NullUUID{Valid: false}
} else {
if err != nil {
return err
}
*nd = NullUUID{s, true}
}
return nil
}
func (nd NullUUID) Value() (driver.Value, error) {
if !nd.Valid {
return nil, nil
}
return nd.Value, nil
}
func (nd NullUUID) MarshalJSON() ([]byte, error) {
if !nd.Valid {
return []byte("null"), nil
}
return json.Marshal(nd.UUID.String())
}
func (nd *NullUUID) UnmarshalJSON(b []byte) error {
var str string
err := json.Unmarshal(b, &str)
if err != nil {
nd.Valid = false
return err
}
id, err := uuid.Parse(str)
if err != nil {
nd.Valid = false
return err
}
nd.UUID = id
nd.Valid = true
return err
}
这段代码还处理了编组和解组,因此它可以打印值或"null",但你可以根据需要进行编辑。
这是我测试过的示例:
id | text
----+------
| sda
// 行结果:
main.Row{Id:main.NullUUID{UUID:uuid.UUID{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}, Valid:false}, Text:main.NullString{String:"sda", Valid:true}}
// 行编组:
{"id":null,"text":"sda"}
// 行解组:
main.Row{Id:main.NullUUID{UUID:uuid.UUID{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}, Valid:false}, Text:main.NullString{String:"", Valid:false}} // 在我的空字符串解组中似乎存在一个错误,但我认为这与本问题无关
以防万一,我还测试了非空的uuid,以下是结果:
// 行编组
{"id":"889f2163-ee59-4632-b238-3ac9574f111e","text":null}
// 行解组
main.Row{Id:main.NullUUID{UUID:uuid.UUID{0x88, 0x9f, 0x21, 0x63, 0xee, 0x59, 0x46, 0x32, 0xb2, 0x38, 0x3a, 0xc9, 0x57, 0x4f, 0x11, 0x1e}, Valid:true}, Text:main.NullString{String:"", Valid:true}} // 再次,在我的空字符串解组中似乎存在一个错误,但我认为这与本问题无关
// 打印的UUID字符串
889f2163-ee59-4632-b238-3ac9574f111e
<details>
<summary>英文:</summary>
So you can declare a custom type to handle uuid (or any other non-default type). I've provided the implementation and it works for me with examples. NOTE: I've already declared a custom type to handle null string but I've left it out for brevity.
Also I did not do a complete test coverage of this code, so please take it as a starting point.
type NullUUID struct {
UUID uuid.UUID
Valid bool
}
func (nd *NullUUID) Scan(value interface{}) (err error) {
var s uuid.UUID
if err := s.Scan(value); err != nil {
return err
}
// if nil then make Valid false
if reflect.TypeOf(value) == nil {
*nd = NullUUID{Valid: false}
} else {
if err != nil {
return err
}
*nd = NullUUID{s, true}
}
return nil
}
func (nd NullUUID) Value() (driver.Value, error) {
if !nd.Valid {
return nil, nil
}
return nd.Value, nil
}
func (nd NullUUID) MarshalJSON() ([]byte, error) {
if !nd.Valid {
return []byte("null"), nil
}
return json.Marshal(nd.UUID.String())
}
func (nd *NullUUID) UnmarshalJSON(b []byte) error {
var str string
err := json.Unmarshal(b, &str)
if err != nil {
nd.Valid = false
return err
}
id, err := uuid.Parse(str)
if err != nil {
nd.Valid = false
return err
}
nd.UUID = id
nd.Valid = true
return err
}
This also handles marshalling and unmarshalling so it either prints the value or "null", but you can edit this is required.
Here is my tested example:
id | text
----+------
| sda
// Row result:
main.Row{Id:main.NullUUID{UUID:uuid.UUID{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}, Valid:false}, Text:main.NullString{String:"sda", Valid:true}}
// Row marshalled:
{"id":null,"text":"sda"}
// Row unmarshalled:
main.Row{Id:main.NullUUID{UUID:uuid.UUID{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}, Valid:false}, Text:main.NullString{String:"", Valid:false}} // seems to be a bug in my null string unmarshalling but I don't think it's relevant here
Just in case, I also tested non null uuid and here is the result:
// Row marshalled
{"id":"889f2163-ee59-4632-b238-3ac9574f111e","text":null}
// Row unmarshalled
main.Row{Id:main.NullUUID{UUID:uuid.UUID{0x88, 0x9f, 0x21, 0x63, 0xee, 0x59, 0x46, 0x32, 0xb2, 0x38, 0x3a, 0xc9, 0x57, 0x4f, 0x11, 0x1e}, Valid:true}, Text:main.NullString{String:"", Valid:true}} // again seems to be a bug in my null string unmarshalling but I don't think it's relevant here
// Printed UUID string
889f2163-ee59-4632-b238-3ac9574f111e
</details>
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论