Невозможно использовать строковый тип как sql .NullString - PullRequest
0 голосов
/ 21 марта 2020

Я создаю gorm модель

// Day is a corresponding day entry
type Day struct {
    gorm.Model
    Dateday   string         `json:"dateday" gorm:"type:date;NOT NULL"`
    Nameday   string         `json:"nameday" gorm:"type:varchar(100);NOT NULL"`
    Something sql.NullString `json:"salad"`
    Holyday   bool           `json:"holyday"`
}

Я использую sql.NullString для поля Something, потому что это может быть NULL.

Поэтому, когда я пытаюсь выполнить типичный gorm пример для проверки моих работ по установке:

    db.Create(&Day{
        Nameday:     "Monday",
        Dateday:     "23-10-2019",
        Something:   "a string goes here",
        Holyday:      false,
    })

Я получаю:

не могу использовать «строка идет сюда», (строка типа) в качестве типа sql .NullString в значении поля

Какой тип я должен использовать для поля Something, если оно может быть NULL?

1 Ответ

1 голос
/ 22 марта 2020

Тип sql.NullString на самом деле является не строковым, а структурным типом. Он определяется как:

type NullString struct {
    String string
    Valid  bool // Valid is true if String is not NULL
}

Поэтому вам нужно инициализировать его следующим образом:

db.Create(&Day{
    Nameday:     "Monday",
    Dateday:     "23-10-2019",
    Something:   sql.NullString{String: "a string goes here", Valid: true},
    Holyday:     false,
})

В качестве альтернативы, если вы хотите продолжать использовать более простой синтаксис при инициализации строки, допускающей значение NULL, вы можете объявить свой собственный тип строки, который может иметь значение NULL, сделать так, чтобы он реализовывал интерфейсы sql.Scanner и driver.Valuer, и использовать нулевой байт для сигнализации значения NULL.

type MyString string

const MyStringNull MyString = "\x00"

// implements driver.Valuer, will be invoked automatically when written to the db
func (s MyString) Value() (driver.Value, error) {
    if s == MyStringNull {
        return nil, nil
    }
    return []byte(s), nil
}

// implements sql.Scanner, will be invoked automatically when read from the db
func (s *String) Scan(src interface{}) error {
    switch v := src.(type) {
    case string:
        *s = String(v)
    case []byte:
        *s = String(v)
    case nil:
        *s = StringNull
    }
    return nil
}

При этом, если вы объявите поле Something типа MyString, вы можете инициализировать его так, как планировали.

db.Create(&Day{
    Nameday:     "Monday",
    Dateday:     "23-10-2019",
    // here the string expression is an *untyped* string constant
    // that will be implicitly converted to MyString because
    // both `string` and `MyString` have the same *underlying* type.
    Something:   "a string goes here",
    Holyday:     false,
})

Просто имейте в виду, что это работает только с нетипизированными константами если у вас есть константа или переменная типа string, чтобы иметь возможность присвоить ее MyString, вам необходимо использовать явное преобразование.

var s string
var ms MyString

s = "a string goes here"
ms = s // won't compile because s is not an untyped constant
ms = MyString(s) // you have to explicitly convert
...