当前位置: 首页 > 面试题库 >

Golang-DTO,实体和映射

丰赞
2023-03-14
问题内容

我是Go语言的新手,具有C#背景并且对如何构造Go应用程序感到困惑。

假设我正在构建一个REST API,它将位于数据库之上。还要说,即使完成后,鉴于业务的变迁等,此应用程序可能仍需要频繁更改。

在带有诸如Entity
Framework和DTO之类的工具的C#中,我通过从控制器给出的结果中抽象出数据库来缓解此问题。如果更改数据库中一堆字段的名称,则可能必须更改数据库访问逻辑,但是希望我使用AutoMapper映射到实体的DTO可以保持不变,因此我不会破坏依赖于前端的功能给定的DTO结构。

我应该用Go的结构复制此结构吗?鉴于结构基本上只是DTO,而我将拥有相当多的DTO结构与实体结构相同,因此这种方法似乎有些错误。我还必须设置逻辑以将实体映射到DTO。某种程度上,这一切都感觉很特别,我在网上看到的许多示例都只是序列化了数据库结构。

简而言之,人们如何避免在API和Go中的数据库之间过度耦合,以及他们如何广泛地分离出应用程序的不同部分?

如果有什么不同,我计划用来sqlx将数据库结果编组为结构体,如果我不将实体与DTO分开的话,除了JSON标记外,还将意味着更多标记。


问题答案:

对于REST API,通常将处理至少三个不同的实现层:

  • HTTP处理程序
  • 某种业务逻辑/用例
  • 持久性存储/数据库接口

您可以分别处理和构建每个组件,这不仅可以使它们解耦,而且还使其更具可测试性。这些部分然后通过注入必要的位组合在一起,因为它们符合您定义的接口。通常这最终离开main或单独配置机制,这是认识的唯一的地方
是什么 被合并并注入 如何

文章“ 将Clean Architecture to
Go应用程序应用”
很好地说明了如何分离各个部分。您应该严格遵循这种方法的程度在一定程度上取决于项目的复杂性。

下面是一个非常基本的细分,将处理程序与逻辑和数据库层分开。

HTTP处理程序

处理程序只需要将请求值映射到局部变量或可能的自定义数据结构中就可以了。除此之外,它只运行用例逻辑并映射结果,然后再将其写入响应。这也是将不同的错误映射到不同的响应对象的好地方。

type Interactor interface {
    Bar(foo string) ([]usecases.Bar, error)
}

type MyHandler struct {
    Interactor Interactor
}

func (handler MyHandler) Bar(w http.ResponseWriter, r *http.Request) {
    foo := r.FormValue("foo")
    res, _ := handler.Interactor.Bar(foo)

    // you may want to map/cast res to a different type that is encoded
    // according to your spec
    json.NewEncoder(w).Encode(res)
}

单元测试是测试HTTP响应是否包含针对不同结果和错误的正确数据的好方法。

用例/业务逻辑

由于只是将存储库指定为接口,因此很容易为业务逻辑创建单元测试,并通过模拟存储库实现返回的不同结果返回结果,该结果也符合DataRepository

type DataRepository interface {
    Find(f string) (Bar, error)
}

type Bar struct {
    Identifier string
    FooBar     int
}

type Interactor struct {
    DataRepository DataRepository
}

func (interactor *Interactor) Bar(f string) (Bar, error) {
    b := interactor.DataRepository.Find(f)

    // ... custom logic

    return b
}

数据库界面

与数据库对话的部分实现了DataRepository接口,但在其他方面完全独立于如何将数据转换为预期的类型。

type Repo {
    db sql.DB
}

func NewDatabaseRepo(db sql.DB) *Repo {
    // config if necessary...

    return &Repo{db: db}
}

func (r Repo)Find(f string) (usecases.Bar, error) {
    rows, err := db.Query("SELECT id, foo_bar FROM bar WHERE foo=?", f)
    if err != nil {
        log.Fatal(err)
    }
    defer rows.Close()

    for rows.Next() {
        var id string, fooBar int
        if err := rows.Scan(&id, &fooBar); err != nil {
            log.Fatal(err)
        }
        // map row value to desired structure
        return usecases.Bar{Identifier: id, FooBar: fooBar}
    }

    return errors.New("not found")
}

同样,这允许单独测试数据库操作,而无需任何模拟SQL语句。

注意: 上面的代码非常伪,而且不完整。



 类似资料:
  • 问题内容: 我们将使用DTO在表示层之间来回发送数据。我们有像这样的图层: facade appService domain 并且我们使用推土机来帮助我们将实体转换为dto。但是我现在有两个问题: 从实体到dto,我们可以使用推土机,但是从dto到实体,我们可以使用推土机吗?如果是,如何? 我应该在哪里创建实体?在外观或DTOAssembler中? 例如,我必须注册一本书。这本书的实体外观如下:

  • 我正在尝试使用AutoMapper在LLBLGen实体和DTO之间创建映射。 我的DTO如下所示: ParentEntity包含一个与DTO列表同名的ChildCollection和一个Id(需要忽略其他LLBL字段)。因此,当ParentEntity映射到父d to时,它也应该将ChildCollection映射到一个子列表。 这就是我到目前为止得到的: 这会导致Id被映射,但List的计数为0

  • 我试图在我的项目中巧妙地使用DTO和实体,但它似乎比它应该的更复杂。我正在构建一个管理库存的后端,我使用NestJs和TypeOrm。 我的客户向我发送了一组数据抛出POST请求,比如: 我的控制器有责任通过使用自定义ValidationPipe检查字段: 我在许多地方读到,在最佳实践中,原始数据应该转换为DTO,当涉及到数据插入时,我应该将DTO转换为类型化实体。 我同意这种方法,但我发现它非常

  • 我有一种情况,在一个DTO中有另一个DTO,我必须映射到它对应的实体。 我正在使用mapstruct,我已经有antherEntityMapper已经存在。 如何更改EntityMapper接口,以便我可以将一个另一个EntityDTO映射到另一个Entity? 谢谢

  • 我正在为我们班做一个项目。需要将DTO映射到实体,反之亦然。我的DTO没有Id字段,转换正在控制器层进行。另外两个类正在扩展我的实体,因此@Superbuilder。 我的转换实体- 但是DTO- 如果你们谁能帮我找到解决办法,我将不胜感激。提前感谢您的时间和回复。 =======我的DTO===== =====我的实体===== } ====ModelMapper的Bean===== =====

  • 我希望在我正在从事的一个项目中使用CQR,但是我目前正在努力寻找实现CQR查询端的最佳方法。基于我有限的理解,有一个瘦数据层(有时称为瘦读取层),用于查询数据库并返回DTO,其中包含应用程序UI层使用的查询结果。 由于这是一个Java的EE应用程序,我正在开发薄数据层,使用JPA使用EntityManager.createNamedQuery查询数据库,返回一个包含结果的实体,然后将其映射到DTO