Golang 中的条件存储库

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

我目前正在运行 Go API,其中有存储库,允许我从 MySQL 数据库获取数据。

但是我想实现相同的存储库来从 MongoDB 数据库获取相同的数据,这对我来说目前很困难。

这是我的代码:

// My vehicle repository file

// Repository handling Vehicle
type VehicleRepository struct {
    conn  *sqlx.DB
}

func (r *VehicleRepository) GetVehicles(ctx context.Context, brand string) (vehicle.Vehicle, error) {
    var vehicles []*vehicle.Vehicle
    param := map[string]interface{}{"brand": brand}

    query := "SELECT * FROM vehicles WHERE brand = :brand"

    rows, err := r.conn.NamedQueryContext(ctx, query, param)
    if err != nil {
        return nil, errors.Wrap(err, "query execution")
    }

    return vehicles, nil
}

// and in another file I create a repository object with all my repository (here only "Vehicle" but in reality I have plenty)
type Repositories struct {
    Vehicle    *VehicleRepository
}

func CreateRepositories(conn c.Connections) *Repositories {
    return &Repositories{
        Vehicles:      &VehicleRepository{conn, l},
    }
}

这段代码运行良好,但它一次只能处理每种情况(无论是在 MySQL 模式还是在 MongoDB 模式下),但我现在需要处理 MySQL 和 MongoDB,并根据我的 API 配置使用 MongoDB 存储库即时更改。

我尝试了多种方法:

1)实施不同的存储库

我尝试重命名我的

vehicle.go
存储库
vehicle.mysql.go
并创建一个
vehicle.mongodb.go
实现 mongodb 存储库。我将
VehicleRepository
结构重命名为
VehicleMySQLRepository
并将
VehicleMongoDBRepository
创建为
vehicle.mongodb.go
,但是当我尝试将其链接到我的
Repositories
中的
CreateRepositories
时,它中断了:

type Repositories struct {
    // Here I have `VehicleRepository` but it didn't exist anymore, and I can't set Vehicle to `VehicleMySQLRepository | VehicleMongoDBRepository`
    Vehicle    *VehicleRepository
}

func CreateRepositories(conn c.Connections, condition bool) *Repositories {
    if condition == true {
        return &Repositories{
            // Here I could do this:
            // Vehicles: &VehicleMySQLRepository{conn.Mysql, l},
            // Vehicles: &VehicleMongoDBRepository{conn.Mongo, l},
            // but it won't work because `Vehicles` will be declared multiple time, and I can't
            // have multiple `Vehicles` like `VehiclesMongo` & `VehiclesMysql`, etc...
            // because it will break all my calls on `Vehicles` in +50 files, and in reality
            // I've got over 30 repositories, if I need to duplicate each ones of them it won't do...

            Vehicles: &VehicleRepository{conn.Mongo, l},
        }
    }
    return &Repositories{
        Vehicles:     &VehicleRepository{conn.Mysql, l},
    }
}

2)条件编译

我想到了我可以创建

vehicle.mysql.go
vehicle.mongodb.go
,实现它们各自的存储库,并且仅使用
go build -tags mongo
和 co 来编译它,它可以工作,但我需要同时处理这两个存储库,在我的前端用户可以选择使用 MySQL 还是 MongoDB 数据库,所以我无法每次都用良好的实现重新编译我的后端。


3)保留相同的存储库

我还尝试不更改存储库,并在函数本身中处理 MySQL 和 MongoDB 连接,就像在

GetVehicles()
方法中一样,
query
字符串有条件地设置为 MySQL 查询或 MongoDB 查询,它可以工作,但实现太恶心了,我真的很想让选项 1) 起作用。


我不知道我的问题是否足够清楚,如果需要更多信息,请随时在评论中索取。

go repository repository-pattern
1个回答
0
投票

为了处理您的情况,您可以在 Go 中使用多态性和接口概念。

  1. Interface:定义一个接口,定义存储库所需的方法。
type VehicleRepository interface {
    GetVehicles(ctx context.Context, brand string) ([]*vehicle.Vehicle, error)
}
  1. 实现:为 MySQL 和 MongoDB 创建单独的实现。
type MySQLVehicleRepository struct {
    conn *sqlx.DB
}

func (r *MySQLVehicleRepository) GetVehicles(ctx context.Context, brand string) ([]*vehicle.Vehicle, error) {
    // Logic for retrieving data from MySQL
}

type MongoDBVehicleRepository struct {
    session *mgo.Session
}

func (r *MongoDBVehicleRepository) GetVehicles(ctx context.Context, brand string) ([]*vehicle.Vehicle, error) {
    // Logic to fetch data from MongoDB
}
  1. 工厂函数:创建工厂函数,根据API配置创建合适的存储库。
func CreateVehicleRepository(conn c.Connections, condition bool) VehicleRepository {
    if condition {
        return &MongoDBVehicleRepository{conn.Mongo}
    }
    return &MySQLVehicleRepository{conn.Mysql}
}

通过这种方法,您可以根据 API 配置创建 MySQL 或 MongoDB 存储库。您可以使用

GetVehicles
接口中的
VehicleRepository
方法,而不必担心底层实现。

这种设计有助于保持存储库逻辑干净并与特定数据库实现分开。这也使得将来在不同数据库后端之间切换更加容易。

© www.soinside.com 2019 - 2024. All rights reserved.