Sto scrivendo un programma di base per leggere i valori dalla tabella del database e stampare nella tabella. Il tavolo era popolato da un programma antico. Alcuni dei campi nella riga sono opzionali e quando provo a leggerli come stringa, ottengo il seguente errore:Come posso gestire i valori di ritorno nil dal database?
panic: sql: Scan error on column index 2: unsupported driver -> Scan pair: <nil> -> *string
Dopo aver letto le altre domande per problemi simili, mi si avvicinò con seguente codice per gestire il valori nulli. Il metodo funziona bene nella pratica. Ottengo i valori in testo normale e stringa vuota invece dei valori nulli.
Tuttavia, ho due preoccupazioni:
- Questo non sembra efficiente. Ho bisogno di gestire più di 25 campi come questo e questo significherebbe che li leggo come byte e li converto in stringa. Troppe chiamate e conversioni di funzioni. Due strutture per gestire i dati e così via ...
- Il codice sembra brutto. Sembra già contorto con 2 campi e diventa illeggibile quando vado a 25+
Sto sbagliando? C'è un modo migliore/più pulito/efficace/idiomatico per leggere i valori dal database?
Trovo difficile credere che un linguaggio moderno come Go non gestisca il database con un ritorno elegante.
Grazie in anticipo!
Codice frammento:
// DB read format
type udInfoBytes struct {
id []byte
state []byte
}
// output format
type udInfo struct {
id string
state string
}
func CToGoString(c []byte) string {
n := -1
for i, b := range c {
if b == 0 {
break
}
n = i
}
return string(c[:n+1])
}
func dbBytesToString(in udInfoBytes) udInfo {
var out udInfo
var s string
var t int
out.id = CToGoString(in.id)
out.state = stateName(in.state)
return out
}
func GetInfo(ud string) udInfo {
db := getFileHandle()
q := fmt.Sprintf("SELECT id,state FROM Mytable WHERE id='%s' ", ud)
rows, err := db.Query(q)
if err != nil {
log.Fatal(err)
}
defer rows.Close()
ret := udInfo{}
r := udInfoBytes{}
for rows.Next() {
err := rows.Scan(&r.id, &r.state)
if err != nil {
log.Println(err)
}
break
}
err = rows.Err()
if err != nil {
log.Fatal(err)
}
ret = dbBytesToString(r)
defer db.Close()
return ret
}
edit:
voglio avere qualcosa come il seguente dove faccio non devono preoccuparsi di gestire NULL e leggerli stringa come vuota automaticamente.
// output format
type udInfo struct {
id string
state string
}
func GetInfo(ud string) udInfo {
db := getFileHandle()
q := fmt.Sprintf("SELECT id,state FROM Mytable WHERE id='%s' ", ud)
rows, err := db.Query(q)
if err != nil {
log.Fatal(err)
}
defer rows.Close()
r := udInfo{}
for rows.Next() {
err := rows.Scan(&r.id, &r.state)
if err != nil {
log.Println(err)
}
break
}
err = rows.Err()
if err != nil {
log.Fatal(err)
}
defer db.Close()
return r
}
Grazie per le risposte. Vedo che molte soluzioni suggeriscono l'uso di sql.NullString o della libreria specifica del database. Desideravo che ci fosse qualcosa di generico che sarebbe stato eseguito su "database/sql". Per il momento userò la soluzione sql.NullString perché devo collegarmi a un database sqlserver remoto via ODBC (lo so, doloroso). – FlowRaja