download12749
download12749
2017-04-03 18:31

Go和MongoDB:通用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条回答

  • dqxyh48864 dqxyh48864 4年前

    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)
    
    点赞 评论 复制链接分享