Gorm:是否可以为常见的数据库操作定义共享方法(例如通过 id 获取)?

Gorm: Is it possible to define shared methods for common db operations (e.g get by id)?

在项目中使用 gogorm

我创建了一个 dao 级别来包装数据库操作,每个 table 都有自己的 dao 类型。


当前代码


我想达到的目标

想知道是否可以用一个 Get() 方法在 go 中编写一个 BaseDao,这样我就不必将这段代码写两次。

这在 Java 中非常容易,但由于 go 非常不同,并且不支持真正的继承(我猜),不确定这是否可能。


我试过的


问题

type BaseDao struct {
    FirstDao
    SecondDao
}

func (dao *BaseDao) Get(id uint64) (*model.SecondModel, error) {
}

只是写下我的想法。这可能会帮助您找到解决方案

如果您试图完全绕过为每个 DAO 编写 Get() 方法,您唯一的解决方案是从该方法中 return 一个 interface{}。 然而,这种方法会产生两个问题:

  • 您需要在所有地方手动投射 interface{}
  • 你正在牺牲类型安全。

我认为最好的解决方案是通过使用结构嵌入来共享大部分代码,并为每个 DAO 编写轻量级包装器以将不安全的 interface{} 转换为类型安全的值。

例子

首先使用通用 Get() 方法创建您的基础 DAO。 Go 中没有类型泛型,所以你应该 return 一个 interface{} 在这里。

type BaseDAO struct {}

func (*BaseDAO) Get(id uint64) (interface{}, error) {}

然后,针对每种类型的数据,创建一个特定的 DAO 实现,嵌入 BaseDAO :

type FooModel = string

type FooDAO struct {
    // Embbeding BaseDAO by not specifying a name on this field
    // BaseDAO methods can be called from FooDAO instances
    BaseDAO
}

func (foo *FooDAO) Get(id uint64) (FooModel, error) {
    // Call the shared Get() method from BaseDAO.
    // You can see this just like a `super.Get()` call in Java.
    result, _ := foo.BaseDAO.Get(id)
    return result.(FooModel), nil
}

也许不能。因为在 go 1.18 之前 go dose 不支持 genrics。

我认为提取 dao 层可能是 anti-pattern,如果你想使用 hook

想象一下:

// pkg models
type User
type UserChangeLog

func (user *User) afterUpdate(tx) error () {
  // if you want to record user changes
  userChangeLogDao().insert(user)
}
// pkg dao
func (userDao) update() {}
func (userChangeLogDao) insert(User){}

它导致 import cycle 在 dao 和模型之间