英文:
Go reflect with gorm library
问题
我正在使用gorm包(https://github.com/jinzhu/gorm)作为我的golang数据库库。我有许多类(数据库表),比如"Hotel"或"Package"。重复代码不是良好的编程实践。举个简单的例子,假设我想从每个表中获取第一个对象。我可以为每个对象编写这个方法(GetFirstHotel
,GetFirstPackage
...)。但更好的方法是只有一个方法GetFirstItem
,我可以使用第一个参数创建与参数相同类的对象,然后将其传递给gorm,gorm会用数据库中的数据填充它,然后将其作为interface{}
返回。我尝试使用反射来实现这一点,但失败了,可能是因为我对它的理解不够。
也许我只是没有发现gorm库中的某些函数,或者我无法正确使用reflect包。我应该如何实现GetFirstItem
函数?是否可能实现这个函数,还是我应该重复我的代码?
package main
import (
"github.com/jinzhu/gorm"
)
var db gorm.DB
type Hotel struct {
ID int64
Name string
Lat float64
Lon float64
}
type Package struct {
ID int64
Name string
Text string
}
func GetFirstHotel() (hotel Hotel) {
db.First(&hotel)
}
func GetFirstPackage() (pack Package) {
db.First(&pack)
}
func main() {
var firstHotel, firstPackage interface{}
//first method
firstHotel = GetFirstHotel()
firstPackage = GetFirstPackage()
//method i want to use
firstHotel = GetFirstItem(Hotel{})
firstPackage = GetFirstItem(Package{})
}
func GetFirstItem(item interface{}) interface{} {
//how to implement this?
//probably with some use of reflect package
}
英文:
I am using gorm package (https://github.com/jinzhu/gorm) as my database library in golang. I have many classes (database tables) like "Hotel" or "Package". Duplicating code is not good programming practice. As a silly example - lets assume I want to get first object from each table. I can write this method (GetFirstHotel
, GetFirstPackage
...) for each object. But better way would be to have just a single method GetFirstItem
, where I would use first param to create object with same class as parameter, then pass it to gorm, which will fill it with data from database, then return it as interface{}
. I tried to use reflect for that, but failed, because I probably don't understand it much.
Maybe I just didn't discover some function in gorm library, or I can't use reflect package properly. How should I implement GetFirstItem
function. Is it possible to have this implemented, or should I rather repeat my code?
package main
import (
"github.com/jinzhu/gorm"
)
var db gorm.DB
type Hotel struct {
ID int64
Name string
Lat float64
Lon float64
}
type Package struct {
ID int64
Name string
Text string
}
func GetFirstHotel() (hotel Hotel) {
db.First(&hotel)
}
func GetFirstPackage() (pack Package) {
db.First(&pack)
}
func main() {
var firstHotel, firstPackage interface{}
//first method
firstHotel = GetFirstHotel()
firstPackage = GetFirstPackage()
//method i want to use
firstHotel = GetFirstItem(Hotel{})
firstPackage = GetFirstItem(Package{})
}
func GetFirstItem(item interface{}) interface{} {
//how to implement this?
//probably with some use of reflect package
}
答案1
得分: 2
db.First方法返回db引用,并将行填充到传递的结构体中。
最接近您所需的方法是:
func GetFirstItem(item interface{}) error {
return db.First(item).Error
}
这只需要您保留对参数的引用:
var firstHotel &Hotel{}
err := GetFirstItem(firstHotel)
要返回所有类型的填充对象,需要类型参数(泛型)。我认为您会发现当前的情况在一定限度内是可行的。
参考链接:https://stackoverflow.com/questions/3912089/why-no-generics-in-go
英文:
The db.First method returns db reference and hydrates the row into the passed structure.
The closest to your desired method is
func GetFirstItem(item interface{}) error {
return db.First(item).Error
}
This simply requires you keep a reference to the parameter
var firstHotel &Hotel{}
err := GetFirstItem(firstHotel)
Returning the hydrated object for all types would required type parameters (generics). I think you'll find the current situation is workable within limits.
see also: https://stackoverflow.com/questions/3912089/why-no-generics-in-go
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论