duanduoding2238 2015-11-25 17:20
浏览 36
已采纳

Golang储存库模式

I try to implement repository pattern in Go app (simple web service) and try to find better way to escape code duplication.

Here is a code

Interfaces are:

type IRoleRepository interface {
    GetAll() ([]Role, error)
}

type ISaleChannelRepository interface {
    GetAll() ([]SaleChannel, error)
}

And implementation:

func (r *RoleRepository) GetAll() ([]Role, error) {
        var result []Role
        var err error
        var rows *sql.Rows

        if err != nil {
            return result, err
        }

        connection := r.provider.GetConnection()
        defer connection.Close()

        rows, err = connection.Query("SELECT Id,Name FROM Position")
        defer rows.Close()

        if err != nil {
            return result, err
        }

        for rows.Next() {
            entity := new(Role)
            err = sqlstruct.Scan(entity, rows)

            if err != nil {
                return result, err
            }

            result = append(result, *entity)
        }
        err = rows.Err()
        if err != nil {
            return result, err
        }

        return result, err
    }

    func (r *SaleChannelRepository) GetAll() ([]SaleChannel, error) {
        var result []SaleChannel
        var err error
        var rows *sql.Rows

        if err != nil {
            return result, err
        }

        connection := r.provider.GetConnection()
        defer connection.Close()

        rows, err = connection.Query("SELECT DISTINCT SaleChannel 'Name' FROM Employee")
        defer rows.Close()

        if err != nil {
            return result, err
        }

        for rows.Next() {
            entity := new(SaleChannel)
            err = sqlstruct.Scan(entity, rows)

            if err != nil {
                return result, err
            }

            result = append(result, *entity)
        }
        err = rows.Err()
        if err != nil {
            return result, err
        }

        return result, err
    }

As you can see differences are in a few words. I try to find something like Generics from C#, but didnt find.

Can anyone help me?

  • 写回答

3条回答 默认 最新

  • duanjupiao4730 2015-11-25 19:25
    关注

    No, Go does not have generics and won't have them in the forseeable future.

    You have three options:

    • Refactor your code so that you have a single function which accepts an SQL statement and another function, and:

      1. Queries the DB with the provided statement.
      2. Iterates over the result's rows.
      3. For each row, calls the provided function whose task is to scan the row.

      In this case, you'll have a single generic "querying" function, and the differences will be solely in "scanning" functions.

      Several variations on this are possible but I suspect you have the idea.

    • Use the sqlx package which basically is to SQL-driven databases what encoding/json is to JSON data streams: it uses reflection on your types to create and execute SQL to populate them.

      This way you'll get reusability on another level: you simply won't write boilerplate code.

    • Use code generation which is the Go-native way of having "code templates" (that's what generics are about).

      This way, you (usually) write a Go program which takes some input (in whatever format you wish), reads it and writes out one or more files which contain Go code, which is then compiled.

      In your, very simple, case, you can start with a template of your Go function and some sort of a table which maps SQL statement to the types to create from the data selected.


    I'd note that your code indeed looks woefully unidiomatic.

    No one in their right mind implements "repository patterns" in Go, but that's sort of okay so long it keeps you happy—we all are indoctrinated to a certain degree with the languages/environments we're accustomed to,—but your connection := r.provider.GetConnection() looks alarming: the Go's database/sql is drastically different from "popular" environments and frameworks so I'd highly recommend to start with this and this.

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(2条)

报告相同问题?

悬赏问题

  • ¥30 这是哪个作者做的宝宝起名网站
  • ¥60 版本过低apk如何修改可以兼容新的安卓系统
  • ¥25 由IPR导致的DRIVER_POWER_STATE_FAILURE蓝屏
  • ¥50 有数据,怎么建立模型求影响全要素生产率的因素
  • ¥50 有数据,怎么用matlab求全要素生产率
  • ¥15 TI的insta-spin例程
  • ¥15 完成下列问题完成下列问题
  • ¥15 C#算法问题, 不知道怎么处理这个数据的转换
  • ¥15 YoloV5 第三方库的版本对照问题
  • ¥15 请完成下列相关问题!