1 回答
TA贡献1946条经验 获得超3个赞
扫描器和评估器接口实际上并不是您自己使用的东西,至少在数据库中存储自定义类型时不是这样。Scan()
我将首先介绍和函数的使用Value()
,然后解决您的问题。
当您获得sql.Row
结果并想要将结果集中的值分配(扫描)到自定义类型的变量中时。文档显示该sql.Row.Scan()
函数接受 0 个或多个类型的参数interface{}
,基本上是任何东西。
在可以扫描值的支持类型列表中,最后一行是重要的一行:
任何实现扫描仪的类型(请参阅扫描仪文档)
通过 function func (ts *Timestamp) Scan(value interface{}) error {
,该Timestamp
类型现在实现了该Scanner
接口,从而允许sql.Row
向该类型分配值。该Scanner
接口的文档位于Scan()
我上面链接的 文档的正下方。
当然,这可以帮助您从数据库读取值,但在存储这些类型时却无济于事。为此,您需要Valuer
接口。如果您还没有猜到,该func (ts Timestamp) Value() (driver.Value, error)
函数确实使您的Timestamp
类型实现了此接口。
该Valuer
接口的要点是允许一种将任何类型转换为 a 的方法driver.Value
,驱动程序可以使用该类型并将其存储在数据库中
解决问题
首先,我必须假设您的协议输出已写入包中v1
。如果不是,它对你来说不会有很好的效果。
有问题的行确实是您标记的行:
u.CreatedAt = time.Now()
首先,User.CreatedAt
类型为Timestamp
,它本身就是一条包含单个时间戳的消息。要将CreatedAt
时间设置为time.Now()
,您需要CreatedAt
正确初始化该字段:
u.CreatedAt = &Timestamp{ Timestamp: ptypes.TimestampNow(), // this returns a PROTOBUF TYPE! }
你已经Scan
在你的函数中这样做了Value
,所以我真的不明白你为什么不在这里这样做......
建议
如果协议输出确实写入了v1
包,我真的真的会删除该User.Create()
函数。事实上,我会直接杀死它。您的协议缓冲区用于通信。通过 RPC 公开您的程序。这是一个 API。这些message
类型本质上是请求和响应对象(如果您愿意的话,可以美化 DTO)。您正在Create
向其中添加此功能,这会将它们变成 AR 类型。它使您的 protobuf 包无法使用。gRPC 的美妙之处在于您可以生成 golang、C++、Python...代码,其他人可以使用这些代码来调用您的程序。如果你让你的 gRPC 包依赖于数据库,就像你所做的那样,我个人永远不会使用它。
- 1 回答
- 0 关注
- 97 浏览
添加回答
举报