如何为golang中的所有实体编写通用的CRUD控制器?

问题描述 投票:0回答:2

我正在使用 GoFiber 创建一个 Go 服务器来从 MySQL 数据库返回数据。我正在使用 GORM 库来保存和从数据库中获取数据。我总共有 8 个实体。我已经为这些实体定义了模型,如下所示

package models

type Account struct {
    ID        uint      `json:"id" gorm:"primary_key;auto_increment;not_null"`
    Name      string    `json:"name"`
    Company   string    `json:"company"`
    GSTIN     string    `json:"gstin"`
    AccountNo string    `json:"accountNo" gorm:"unique"`
    IFSC      string    `json:"ifsc"`
    CreatedAt time.Time `json:"createdAt"`
    UpdatedAt time.Time `json:"updatedAt"`
}

现在,对于每个实体,我正在编写 4 个控制器方法:创建、更新、列表、删除。每个实体的代码基本上相同,只是实体名称发生了变化。

package controllers

// GET: List call
func GetAccounts(c *fiber.Ctx) error {
    accounts := new([]models.Account)
    result := database.DB.Find(accounts)
    if result.Error != nil {
        return result.Error
    }
    c.SendStatus(http.StatusOK)
    return c.JSON(accounts)
}

// POST
func CreateAccount(c *fiber.Ctx) error {
    account := new(models.Account)
    err := c.BodyParser(account)
    if err != nil {
        return err
    }
    result := database.DB.Create(account)
    if result.Error != nil{
        return result.Error
    }
    return c.SendStatus(http.StatusCreated)
}

现在,像这样,我已经编写了 8 x 4 =32 个控制器方法。所有代码都有重复的代码,只是实体名称发生了变化。

我还手动为每个控制器定义了路线。

    app.Post("api/account", controllers.CreateAccount)
    app.Get("api/accounts", controllers.GetAccounts)

肯定有更好的方法来做到这一点。我不太确定如何这样做或实施它。我应该定义哪些接口,应该嵌入哪些结构,或者做什么?

go design-patterns crud go-gorm go-fiber
2个回答
0
投票

您可以使用泛型。请参阅下面的示例。

T
代表要创建的数据类型。

func Create[T any](c *fiber.Ctx, data T) error {
    result := database.DB.Create(data)
    if result.Error != nil {
        return result.Error
    }

    return nil
}

0
投票

你可以这样做:

func Get[T any]() fiber.Handler {
    return func(c *fiber.Ctx) error {
        models := new([]T)
        result := database.DB.Find(models)
        if result.Error != nil {
           return result.Error
        }
        c.SendStatus(http.StatusOK)
        return c.JSON(models)
    }
}

func Create[T any]() fiber.Handler {
    return func(c *fiber.Ctx) error {
        model := new(T)
        err := c.BodyParser(model)
        if err != nil {
            return err
        }
        result := database.DB.Create(model)
        if result.Error != nil{
            return result.Error
        }
        return c.SendStatus(http.StatusCreated)
    }
}

然后对于路由,您必须以这种方式调用处理程序:

app.Post("api/account", controllers.Create[models.Account]())
app.Get("api/accounts", controllers.Get[models.Account]())
© www.soinside.com 2019 - 2024. All rights reserved.