当前位置: 首页 > 知识库问答 >
问题:

每个实体的DTO对象

壤驷宏才
2023-03-14

我继承了一个用Java编写的应用程序,该应用程序使用JPA访问数据库。该应用程序使用了一种我以前从未遇到过的设计模式,并且我会真正了解为什么使用此模式的一些指导。与许多应用程序一样,我们有一个前端、中间件和后端数据库。数据库通过 DAO 访问。DAO上的每个方法都加载一个实体DTO,它只是一个POJO,除了获取器和设置器之外什么都没有,然后该实体DTO被传递到具有更改实体状态的其他方法的实体中。示例 [为保护同义词而更改了类名]

enum Gender
{
    Male,
    Female
}

class PersonDTO
{
    private String mFirstName;
    private String mLastName;
    private Gender mGender;
    ...

    String getFirstName() { return this.mFirstName; }
    String setFirstName(String name) { this.mFirstName = name; }
    // etc
}

class Person
{
    PersonDTO mDTO;
    Person(PersonDTO dto)
    {
        mDTO = dto;
    }

    String getFirstName() { return mDTO.getFirstName() }
    String setFirstName(String name) { mDTO.setFirstName(name); }
    // and so on

    void marry( Person aNotherPerson )
    {
        if( this.getGender()==Gender.Female && 
               aNotherPerson.getGender()==Gender.Male)
        {
            this.setLastName( aNotherPerson.getLastName() );
        }
        aNotherPerson.marry( this );
    }
}

这在30个左右的实体类中重复,在DTO中翻了一番,达到60个,我只是不明白为什么。我理解(一点)关于converns的分离,我也理解(一点)关于基于EAO的设计和基于活动记录的设计之间的区别。

但它真的必须走这么远吗?是否应始终至少有一个“DB”对象,该对象只包含映射到 DB 字段的获取器和设置器?

共有3个答案

李博达
2023-03-14

这似乎不是一个已知的模式。

通常

    < li >通常维护一个单独的对象来表示数据库中的记录,称为域对象。 < li >对象上的CRUD操作是DAO类的一部分,其他业务操作是Manager类的一部分,但是这些类都不将域对象存储为成员变量,即DAO和Manager都不携带状态。它们只是处理作为参数传入的域对象的元素。 < Li > DTO用于前端和后端之间的通信,以呈现数据库中的数据或接受最终用户的输入 < li > DTOs由管理器类转换为域对象,其中根据业务规则执行验证和修改。这种域对象使用DAO类保存在DB中。
芮化
2023-03-14

也可能是他们只是使用它来将JPA注释从富域对象中分离出来。

所以我猜有人不喜欢在一个类中有JPA注释和富域对象行为。有人也可能认为JPA注释和富域对象不应该在同一层(因为注释混合了关注点),所以如果你赢了这个论点,你会得到这种分离。

您会看到这种情况发生的另一个地方是,您希望从富域对象中抽象出类似的注释(例如,web服务中的jaxb注释)。

因此,其目的可能是DTO作为某种从代码到数据库的序列化机制,这与martin fowler在这里提到的目的非常相似。

田昊天
2023-03-14

免责声明:关于这个问题有不同的观点,根据您的系统架构,您可能没有选择的余地。

话虽如此……我以前见过这种模式的实现,但并不太喜欢它,在我看来,它是在不增加任何实际价值的情况下复制大量代码。它似乎在具有SOAP等XML API的系统中特别流行,在这些系统中,可能很难将XML结构直接映射到您的对象结构。在您的特定情况下,情况似乎更糟,因为在重复的getFirstName()/getLastName()方法之上,有业务逻辑(属于服务层)直接编码到pojo(应该是像DTO这样的简单数据搬迁对象)中。为什么pojo应该知道只有异性才能结婚?

为了帮助更好地理解原因,您能解释一下这些DTO来自哪里吗?是否有前端将数据提交到控制器,然后控制器将其转换为DTO,然后用于用数据填充实体本身?

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

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

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

  • 在普通的DDD项目中,我希望从存储库中检索到的实体作为DTO从域层发送到应用层。 CQR存在的一个原因似乎是,应用层所需的查询(主要是读取操作)与域层所需的查询不同。因此,即使是同一对象的查询结果在不同层之间也可能不同。 在我的域层中,我已经将查询结果映射到域实体中。我对一些CQRS示例将查询结果直接映射到跳过匹配实体的DTO感到困惑。 假设数据库返回: 但是,实体布局将姓氏映射为姓氏: 如果在我

  • 如果实体之间存在继承,那么我应该如何在DTO中表示它?例如: 我应该如何使用它们?例如,我发现:我正在做一个web项目。网页的用户想要注册。他/她填写表单,并将其发送到服务器。在服务器端,我首先创建一个DTO,因为它的字段有验证。我从DTO创建一个实体并将其持久化到数据库中。当有对实体的请求时,我将被请求的实体转换为DTO,并将其提供给客户端的用户。这是一个很好的想象,还是不是?

  • 问题内容: 我有一个实体- 。由描述。 Hibernate为每个实体创建一个表,因此当我调用时,我的数据总是保存到该表中。 现在,我需要另一个表来存储相同类型的数据,并且只需要将我的实体保存到该表中。 数据结构 (类似这样): 使用这个 : 和结果,我应该在和 中。 由于系统限制,我无法将这两个对象放在一个表中。(即使创建额外的字段也是个坏主意)。 我可以不进行子类化吗?使用Programmati