将gorm中的UUID字段设置为NULL。

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

Setting UUID field to NULL with gorm

问题

我正在使用的数据库是PostgreSQL,ORM是gorm。我有一个包含assigned_id字段的数据库表,该字段的类型是uuid

我想知道如何将assigned_id设置为NULL

我尝试在模型中将该字段设置为nil,还尝试使用gorm.Expr("NULL")nilsql.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&#39;ve provided the implementation and it works for me with examples. NOTE: I&#39;ve already declared a custom type to handle null string but I&#39;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(&quot;null&quot;), nil
    	}
    
    	return json.Marshal(nd.UUID.String())
    }
    
    func (nd *NullUUID) UnmarshalJSON(b []byte) error {
    	var str string
    
    	err := json.Unmarshal(b, &amp;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 &quot;null&quot;, 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:&quot;sda&quot;, Valid:true}}

    // Row marshalled:
    {&quot;id&quot;:null,&quot;text&quot;:&quot;sda&quot;}

    // 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:&quot;&quot;, Valid:false}} // seems to be a bug in my null string unmarshalling but I don&#39;t think it&#39;s relevant here

Just in case, I also tested non null uuid and here is the result:

    // Row marshalled
    {&quot;id&quot;:&quot;889f2163-ee59-4632-b238-3ac9574f111e&quot;,&quot;text&quot;: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:&quot;&quot;, Valid:true}} // again seems to be a bug in my null string unmarshalling but I don&#39;t think it&#39;s relevant here

    // Printed UUID string
    889f2163-ee59-4632-b238-3ac9574f111e

</details>



huangapple
  • 本文由 发表于 2022年12月22日 08:44:06
  • 转载请务必保留本文链接:https://go.coder-hub.com/74883154.html
匿名

发表评论

匿名网友

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

确定