实体和数据传输对象(DTO)的区别

94

DTO和实体之间有什么区别? 这是我想问的问题:

  1. DTO应该包含哪些字段?例如,我的实体类是:

    @Entity
    public class MyFirstEntity implements Serializable {
    
        @Id @GeneratedValue
        private Long id;
    
        private String stringData;
    
        @OneToOne
        private MySecondEntity mySecondEntity;
    
        @OneToMany
        private List<MySecondEntity> mySecondEntitesList;
    
    }
    
    @Entity
    public class MySecondEntity implements Serializable {
    
        @Id @GeneratedValue
        private Long id;
    
        private Integer integerData;
    
        @ManyToOne
        private MyFirstEntity myFirstEntity;
    
    }
    

MyFirstDTOMySecondDTO 类中,应该放置单向连接(一对一)和双向连接(多对一)、简单的字符串和整数数据,当然也要包括 ID。

  1. 如果实体之间存在继承关系,那么我应该如何在 DTO 中表示它?例如:

@Entity
public class MyFirstEntity extends MySecondEntity {
    ....
}

@Entity
public class MyFirstDTO extends MySecondDTO {
    ....
}
  • 我应该如何使用它们?例如,我发现这个问题:我正在开发一个网页项目。网页用户想要注册。他/她填写表单,并将其发送到服务器。在服务器端,我首先创建一个DTO,因为它的字段具有验证功能。从DTO中创建实体并将其持久化到数据库中。当有一个实体的请求时,我将所请求的实体转换为DTO,并将其提供给客户端用户。这是一个好的想象吗?


  • 2
    你看过这里与DTO相关的其他几十个问题吗?比如这个 - Kayaman
    我已经阅读过了。我只是想在这些具体的示例中确保一下。 - Display Name
    4
    你提供的链接页面甚至没有提到我所问的问题。 - Display Name
    1
    例如,关于id、实体之间的连接以及继承等方面没有提及。 而且,我最后一个问题是具体的。 - Display Name
    这是关于DTO和实体的详细解释,附有现实生活示例。https://youtu.be/MKowHmVWqAc - Parveen
    显示剩余2条评论
    4个回答

    113

    简短回答:

    • 实体可能是业务域的一部分。因此,它们可以实现行为并应用于该域内的不同用例。

    • DTO仅用于在进程或上下文之间传输数据。因此,除了非常基本且通常标准化的存储和检索功能外,它们没有行为。

    详细回答:

    虽然“数据传输对象”(DTO)这个术语定义得相当明确,但“实体”这个术语在各种上下文中的解释是不同的。

    我认为,“实体”这个术语最相关的解释有以下三点:

    1. 在实体关系和ORM框架,特别是企业Java和Jpa的上下文中:
      “表示数据库中维护的持久数据的对象。”

    2. 在“领域驱动设计”(Eric Evans)的背景下:
      “主要通过其身份而不是属性来定义的对象。”

    3. 在“干净架构”(Robert C. Martin)的背景下:
      “封装企业范围的重要业务规则的对象。”

    Jee和Jpa社区认为实体主要是映射到数据库表的对象,而领域驱动设计更强调实体的身份和业务规则。无论如何,实体通常具有行为并且可以应用于不同的用例中,而DTO仅用于数据传输。

    一个数据库表。这一观点与DTO的定义非常接近,这也可能是许多混淆的源头。

    在领域驱动设计的上下文中,以及罗伯特·马丁的观点中,实体是业务领域的一部分,因此可以和应该实现行为。


    很棒的答案!不过我想再加几个链接:https://enterprisecraftsmanship.com/2015/04/13/dto-vs-value-object-vs-poco/ - Tharanga Hewavithana
    2
    我在理解DTO和实体应该如何实现方面遇到了一些困难。在这篇博客文章中,R. Martin说DTO是数据结构。因此ORM框架不会构建业务对象,而是提取业务对象操作的数据。但是我该如何正确地实现这种区分呢?我应该定义一个包含ORM提取的EmployeeDTO的EmployeeEntity吗?我一直认为我的实体类(业务对象)必须由ORM映射。 - Melkor
    “JEE 和 JPA 社区主要将实体视为映射到数据库表的对象。” - 只有 JEE 和 JPA 吗?我不这么认为。内置于 .Net 的 ORM 称为 Entity Framework - 因此在 C#/.Net 世界中也发生了同样的事情。 - mvmn
    仅澄清一下,这里的业务领域是指服务层到数据层之后的任何内容,这是您所要表达的意思吗?此外,您所说的行为是指什么? - Eric Huang
    1
    不,三层架构与我的陈述几乎没有任何关系。 "业务领域"是指从“现实世界”中对对象及其行为进行建模的通用术语。如果您在公司工作,那么“业务”或多或少是您正在尝试实现其要求的“现实世界”。该术语形成了与“技术领域”的对比,后者涉及纯粹的技术事物。以下是一个带有更多详细信息和示例的帖子:https://softwareengineering.stackexchange.com/a/314839 - Andreas Vogl
    正如 @mvmn 正确指出的那样,我关于“Jee和Jpa”的陈述不必要地局限于Java世界。 我刚刚编辑了我的帖子以提及ER和ORM框架。 - Andreas Vogl

    61

    DTO和Entity的区别:

    Entity是映射到表格的类,而DTO通常是映射到“视图”层的类。 需要存储的是Entity,而需要在网页上“显示”的是DTO。

    例如:如果我想要将员工模型存储如下: 以员工为例,我需要存储性别,可以是男/女/其他。 但在JSP上,我需要将这三个值都显示为表单“选项”,以便用户选择其中一个。

    @Entity
    public class Employee{
    //annotate with @Id and others
    
    private Long id;
    private String name;
    private Gender gender; //this is enum viz Male,female
    }
    //Now extend Dto with employee
    
    public EmployeeDto extends Employee{
    Gender[] genders=Gender.values(); //put all gender types in array.
    }
    

    在渲染 JSP 时,我们可以提供

    <select name="gender"> //pointed towards entity gender field.
      <option value="Male">Male</option>
      <option value="Female">Female</option>
      <option value="Other">Other</option>
    </select>
    

    然后在spring或其他框架中,选择的性别将被选为实体的一部分。这是由于Dto中包含了所有三个性别值的缘故。 同样,根据情况进行相应的事情。 由于我们大多数时候需要jsp上的大多数实体字段,所以我们通过实体扩展Dto。


    21
    DTO通常被称为通过架构边界传递数据的对象。虽然它们可用于将数据传输到表示层,但它们并不仅限于此特定用法。 - sepehr
    正确的,DTO也可以表示数据库中的记录。 - felipeaf
    我认为你的回答假设你正在实现领域驱动设计?是这样吗?我认为“实体”可能是从ORM角度引用的DatabaseEntities。 - K-Dawg

    11
    简单来说: DTO代表数据传输对象。DTO主要用于在服务(Web服务、API等)之间传输数据,可以包含不同实体的各种属性(带或不带其ID)。以一行DTO为例:假设一个购物网站将通过Web服务向运输公司发送其发货请求。它的DTO会像这样:CustomerFullNameShippingFeeShippingAddress。在此示例中,CustomerFullNameCustomer实体的FirstName+LastName属性的组合,而ShippingFee是目的地、税收等多个实体的一些过程的结果。
    相反,实体是一堆属性集合,用于表示具有特定ID的单个实体(例如TeacherStudentEmployee等)。换句话说,DTO是一堆无意义的属性集合,用于发送到客户端,而DTO不一定与其他DTO具有关系,而实体包括具有有意义关系的特定对象的属性。在关系数据库范例中,我们可以将DTO视为视图行,而实体是具有主键的表格行。@Shatayu Darbhe也在他/她的答案中提到了这一点。
    然而,模型是两者的结合。模型可以包含几个相关实体以及额外的数据来处理现实世界的应用程序/UI问题。考虑一个名为CustomerOrdersModel的模型,它包含Customer实体、List<Order>实体和一个额外的布尔标志PayWithCredit,指定用户是否将使用借记卡或信用卡付款。

    1
    很好的想法,添加了模型定义。 - tfont

    7
    "Entities" 指代整个系统数据的组成单元。它们通常代表业务对象,如银行账户、员工、产品等。它们可以用于将系统状态持久化到数据库中。
    "Data transfer objects" 是传输用于特定目的的短暂数据集合。例如,向最终用户显示特定种类的产品列表。您不希望向用户发送表示每个产品实体的全部数据,而只需发送此目的所需的内容。 Microsoft 2014 MVC文档 解释了为什么要从实体创建DTO。以下是他们建议您执行的一些示例,以将实体转换为DTO。
    • 删除循环引用。
    • 隐藏客户端不应查看的特定属性。
    • 省略某些属性以减少有效负载大小。
    • 展平包含嵌套对象的对象图,以使其更方便客户端使用。
    • 避免 "过度发布" 漏洞。 (有关过度发布的讨论,请参见模型验证。)
    • 将服务层与数据库层解耦。
    但是需要理解的是,这些都不是必须遵循的严格规则。一切取决于哪些数据最适合发送给客户端以及什么格式对客户端最有用。

    客户端需要使用这些数据做什么?

    • 它将被编辑还是只是查看?
    • 客户端是否关心int列表的顺序?
    • 是否需要插入或删除int?
    • 列表是否需要重新排列?

    客户端是否需要知道1-1或1-many关系或继承的事实?发送这些信息可能只会为客户端增加不必要的复杂性。

    在决定发送什么数据以及如何发送之前,需要回答这些和其他问题。


    网页内容由stack overflow 提供, 点击上面的
    可以查看英文原文,
    原文链接