【问题标题】:Confused about custom types in SQL when sql.DB.Execsql.DB.Exec 时对 SQL 中的自定义类型感到困惑
【发布时间】:2015-07-28 10:16:57
【问题描述】:

有这个表结构:

CREATE TABLE `tableName` (
    `Id` int unsigned NOT NULL AUTO_INCREMENT PRIMARY KEY,
    `Status` enum('pending','rejected','sent','invalid') NOT NULL,
    `Body` varchar(255) NULL
) ENGINE='MyISAM' COLLATE 'utf8_general_ci';

我有这个(不完整的)代码工作正常

type StatusEnum string

const (
    STATUS_PENDING  StatusEnum = "pending"
    STATUS_REJECTED StatusEnum = "rejected"
    STATUS_SENT     StatusEnum = "sent"
    STATUS_INVALID  StatusEnum = "invalid"
)

func (s *StatusEnum) Scan(src interface{}) error {
    if src == nil {
        return errors.New("This field cannot be NULL")
    }

    if stringStatus, ok := src.([]byte); ok {
        *s = StatusEnum(string(stringStatus[:]))

        return nil
    }

    return errors.New("Cannot convert enum to string")
}

func (s *StatusEnum) Value() (driver.Value, error) {
    return []byte(*s), nil
}

type EmailQueue struct {
    Id        uint64
    Status    StatusEnum
    Body      sql.NullString
}

func Save (db *sql.DB) error {
    _, err = db.Exec(
        "UPDATE `tableName` SET `Status` = ?, `Body` = ? WHERE `id` = ?",
        &eqi.Status,
        eqi.Body,
        eqi.Id,
    )

    return err
}

所以我的问题是:为什么我需要在db.Exec 上使用指针引用(&eqi.Status)?

sql.NullString 和我自定义的StatusEnum 都没有在github.com/go-sql-driver/mysql 中实现,那为什么会有区别呢?

如果我不使用指针引用 (eqi.Status),我会收到此错误(抛出 database/sql/convert.go):

sql: converting Exec argument #0's type: unsupported type emailqueue.StatusEnum, a string

我正在尝试实现一些我没有找到的其他接口。

我还有其他使用sql.Scannersql.driver.Valuer 接口实现的自定义类型,但问题是一样的。

我在猜测 struct 和类型继承区分,但我无法得到任何提示...... :(

请帮助了解发生了什么。谢谢!!! :)

【问题讨论】:

    标签: mysql sql types go custom-type


    【解决方案1】:

    您为您的StatusEnum 类型实现Valuer interface,就像在*StatusEnum 上操作一样。因此,当您将一个作为参数传递给 Exec 时,它仅作为指针才有意义,因为只有指向 StatusEnum 的指针才实现 Value(),需要内联尊重。

    您没有EmailList 类型的定义,因此我可以建议您更改给定的Valuer 接口。

    func (s StatusEnum) Value() (driver.Value, error) {
        return []byte(s), nil
    }
    

    这是标准库implements 自定义可空类型。

    【讨论】:

    • 抱歉,我修复了将 EmailList 替换为 StatusEnum 的代码。这更令人困惑,因为这段代码完美地工作:v, err := eqi.Status.Value() v, err = (&eqi.Status).Value()
    • 对于任何进来阅读的人来说,这是因为您可以在非指针值上调用指针方法,它会自动获取地址,但前提是它是非接口方法,即变量是一个接口。 golang.org/ref/spec#Method_values
    猜你喜欢
    • 2012-04-24
    • 1970-01-01
    • 2011-01-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-03-22
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多