使用gorm库进行反射操作

huangapple go评论91阅读模式
英文:

Go reflect with gorm library

问题

我正在使用gorm包(https://github.com/jinzhu/gorm)作为我的golang数据库库。我有许多类(数据库表),比如"Hotel"或"Package"。重复代码不是良好的编程实践。举个简单的例子,假设我想从每个表中获取第一个对象。我可以为每个对象编写这个方法(GetFirstHotelGetFirstPackage...)。但更好的方法是只有一个方法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

huangapple
  • 本文由 发表于 2016年2月16日 00:40:24
  • 转载请务必保留本文链接:https://go.coder-hub.com/35414556.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定