英文:
Go and MongoDB: generic DAO implementation issue
问题
在当前项目中,我们使用Go语言和mgo驱动程序连接MongoDB。对于每个实体,我们都需要实现DAO来进行CRUD操作,而且基本上都是复制粘贴的,例如:
func (thisDao ClusterDao) FindAll() ([]*entity.User, error) {
session, collection := thisDao.getCollection()
defer session.Close()
result := []*entity.User{} //创建一个新的空切片来返回结果
q := bson.M{}
err := collection.Find(q).All(&result)
return result, err
}
对于其他实体,代码基本相同,只是结果类型不同。
由于Go语言没有泛型,我们如何避免代码重复呢?
我尝试将result interface{}
参数传递给方法,而不是在方法中创建它,并像这样调用方法:
dao.FindAll([]*entity.User{})
但是,collection.Find().All()
方法需要一个切片作为输入,而不仅仅是接口:
[restful] recover from panic situation: - result argument must be a slice address
/usr/local/go/src/runtime/asm_amd64.s:514
/usr/local/go/src/runtime/panic.go:489
/home/dds/gopath/src/gopkg.in/mgo.v2/session.go:3791
/home/dds/gopath/src/gopkg.in/mgo.v2/session.go:3818
然后,我尝试将参数result []interface{}
,但在这种情况下,无法传递[]*entity.User{}
:
无法将类型为[]*entity.User的[]*entity.User直接作为类型为[]interface {}的参数传递给thisDao.GenericDao.FindAll
有什么办法可以在Go语言中实现通用的DAO吗?
英文:
In the current project we use Go and MongoDB via mgo driver.
For every entity we have to implement DAO for CRUD operations, and it's basically copy-paste, e.g.
func (thisDao ClusterDao) FindAll() ([]*entity.User, error) {
session, collection := thisDao.getCollection()
defer session.Close()
result := []*entity.User{} //create a new empty slice to return
q := bson.M{}
err := collection.Find(q).All(&result)
return result, err
}
For every other entity it's all the same but the result type.
Since Go has no generics, how could we avoid code duplication?
I've tried to pass the result interface{}
param instead of creating it in the method, and call the method like this:
dao.FindAll([]*entity.User{})
but the collection.Find().All()
method need a slice as the input, not just interface:
[restful] recover from panic situation: - result argument must be a slice address
/usr/local/go/src/runtime/asm_amd64.s:514
/usr/local/go/src/runtime/panic.go:489
/home/dds/gopath/src/gopkg.in/mgo.v2/session.go:3791
/home/dds/gopath/src/gopkg.in/mgo.v2/session.go:3818
Then I tried to make this param result []interface{}
, but in that case it's impossible to pass []*entity.User{}
:
>cannot use []*entity.User literal (type []*entity.User) as type []interface {} in argument to thisDao.GenericDao.FindAll
Any idea how could I implement generic DAO in Go?
答案1
得分: 2
你应该能够将一个result interface{}
传递给你的FindAll
函数,并将其直接传递给mgo的Query.All方法,因为参数的类型应该是相同的。
func (thisDao ClusterDao) FindAll(result interface{}) error {
session, collection := thisDao.getCollection()
defer session.Close()
q := bson.M{}
// 将result直接传递,不要在这里使用&
// 因为那将是一个指向接口的指针,而不是指向底层切片的指针,mgo可能不喜欢这样
return collection.Find(q).All(result)
}
// ...
users := []*entity.User{}
if err := dao.FindAll(&users); err != nil { // 在这里传递切片的指针
panic(err)
}
log.Println(users)
英文:
You should be able to pass a result interface{}
to your FindAll
function and just pass it along to mgo's Query.All method since the argument's would have the same type.
func (thisDao ClusterDao) FindAll(result interface{}) error {
session, collection := thisDao.getCollection()
defer session.Close()
q := bson.M{}
// just pass result as is, don't do & here
// because that would be a pointer to the interface not
// to the underlying slice, which mgo probably doesn't like
return collection.Find(q).All(result)
}
// ...
users := []*entity.User{}
if err := dao.FindAll(&users); err != nil { // pass pointer to slice here
panic(err)
}
log.Println(users)
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论