30

我正在考虑使用 DTO 而不是传递我的域对象。我已经在这里和其他地方阅读了几篇文章,我知道有几种方法可以完成这项工作。

如果我总共只有大约 10 个域类,并且考虑到我想在我的视图(WPF 前端)中使用 DTO 而不是域对象来消费,那么推荐的方法是什么。我认为使用 automapper 等工具对我的情况来说可能有点过头了。所以我正在考虑编写我的自定义映射器类,该类将具有将域类型转换为 DTO 类型的方法。

最好的方法是什么,是否有任何样本可以让我开始这样做?

第二个问题:在编写那些将创建 DTO 的方法时,我如何处理设置所有数据,尤其是当域类型引用其他域对象时?我是否在 DTO 中编写等效属性以映射到域类中的那些引用类型?请问我的第二个问题是否用恰当的语言表达。但我想你明白我想问什么。

第三个问题:在编写 DTO 时,我应该编写多个 DTO,每个 DTO 都包含给定域模型的部分数据,以便每个 DTO 都可以用来满足特定 View 的要求,还是 DTO 应该拥有那里的所有数据在相应的模型类中。

4

7 回答 7

13

我在这里阅读了一些关于 DTO 的帖子,在我看来,很多人将它们等同于我认为的 ViewModel。DTO 就是这样,数据传输对象——它是通过网络传递的。所以我有一个网站和服务,只有服务才能访问真正的域/实体对象,并返回 DTO。这些可能是 1:1 映射的,但考虑到 DTO 可能是从另一个服务调用、数据库查询、读取配置等填充的。

之后,网站可以获取这些 DTO 并将它们添加到 ViewModel 中,或者转换为一个。该 ViewModel 可能包含许多不同类型的 DTO。一个简单的示例是任务管理器 - ViewModel 包含您正在编辑的任务对象,以及可以分配任务的一组 Dto.User 对象。

请记住,返回 DTO 的服务可能被网站使用,也可能被平板电脑或手机应用程序使用。这些应用程序将有不同的视图来利用它们的显示,因此 ViewModel 会有所不同,但 DTO 将保持不变。

无论如何,我喜欢这些类型的讨论,所以任何人都请让我知道你的想法。

马特

于 2011-08-25T18:21:07.013 回答
4

我有点在项目中使用 DTO。我倾向于使 DTO 仅显示指定视图所需的数据。我在我的数据访问类中获取视图中显示的所有数据。例如,我可能有一个 Order 对象,它引用了一个 Client 对象:

public class Client{
    public int Id{get;set;}
    public string Name{get;set;}
}

public class Order{
    public int OrderID{get;set;}
    public Client client{get;set;}
    public double Total{get;set;}
    public IEnumerable<OrderLine> lines {get;set;}
}

然后在我的 OrderListDTO 中,我可能有类似的东西:

public class OrderListDTO{
    public int OrderId{get;set;}
    public string ClientName{get;set;}
    ...
 }

我想在我的视图中显示哪些字段。我在我的数据库访问代码中获取所有这些字段,因此我不必为视图或控制器代码中的实体关联而烦恼。

于 2009-09-06T14:26:45.323 回答
3

开发 DTO 的最佳方式

开始开发 DTO 的方法是了解它们的唯一目的是将业务实体的数据子集传输到不同的客户端(可能是 UI 或外部服务)。鉴于这种理解,您可以为每个客户端创建单独的包......并编写您的 DTO 类。对于映射,您可以编写自己的映射器定义接口,以将其传递给创建 DTO 对象的工厂,该对象基于将从正在为其创建 DTO 的实体中提取的数据。您还可以定义要放置在实体字段上的注释,但根据个人使用的注释数量,我更喜欢接口方式。关于 DTO 需要注意的主要是它们也是类,DTO 之间的数据应该被重用,

入门

关于如上所述的入门,DTO 的唯一目的是为客户提供所需的数据....所以请记住,您可以使用 setter 将数据设置到 dto...或定义一个创建一个工厂基于接口的实体的 DTO .....

关于您的第三个问题,请按照客户的要求进行:)

于 2017-03-12T16:23:29.080 回答
1

我来项目,spring-jdbc并使用了DAO层。有时现有实体并未涵盖数据库中所有可能的数据。所以我开始使用DTO

通过应用 '70 结构编程规则,我将所有 DTO 放入单独的包中:

package com.evil.dao;     // DAO interfaces for IOC.
package com.evil.dao.impl; // DAO implementation classes.
package com.evil.dao.dto; // DTOs

现在我重新考虑并决定将所有 DTO 作为内部类放在 DAO 接口上,用于没有重用的结果集。所以DAO界面看起来像:

interface StatisticDao {
    class StatisticDto {
        int count;
        double amount;
        String type;

        public static void extract(ResultSet rs, StatisticDto dto) { ... }
    }

    List<StatisticDto> getStatistic(Criteria criteria);
}


class StatisticDaoImpl implements StatisticDao {
    List<StatisticDto> getStatistic(Criteria criteria) {
        ...
        RowCallbackHandler callback = new RowCallbackHandler() {
            @Override
            public void processRow(ResultSet rs) throws SQLException {
                StatisticDao.StatisticDto.extract(rs, dto);
                // make action on dto
            }
        }
        namedTemplate.query(query, queryParams, callback);
    }
}

我认为将相关数据保存在一起(带有 DAO 接口的自定义 DTO)使PageUp/的代码更好PageDown

于 2014-02-05T15:23:08.970 回答
1

问题 1:如果您需要传输的 DTO 只是域对象的一个​​简单子集,您可以使用模型映射器来避免使用无逻辑映射填充您的代码库。但是,如果您需要对映射应用一些逻辑/转换,请自己进行。

问题 2:您可以并且可能应该为您在主 DTO 上的每个域对象创建一个 DTO。一个 DTO 内部可以有多个 DTO,一个用于您需要映射的每个域对象。并映射那些你可以自己做的,甚至使用一些模型映射器。

问题 3:如果您的视图不需要,请不要公开您的所有域。此外,您不需要为每个视图创建一个 DTO,尝试创建公开需要公开的内容的 DTO,并且可以重复使用以避免多个共享大量信息的 DTO。但这主要取决于您的应用程序需求。

如果您需要澄清,请询问。

于 2019-10-03T15:05:20.297 回答
0

我将假设您的域模型对象有一个主键 ID,该主键 ID 可能对应于它们来自的数据库或存储中的 ID。

如果上述情况属实,那么您的 DTO 将以外键 ID 的形式克服对其他 DTO 的类型引用,就像您的域对象所做的那样。因此,域对象上的 OrderLine.OrderHeader 关系将是 DTO 中的 OrderLine.OrderHeaderId。

希望有帮助。

我能问一下为什么您选择在视图中使用 DTO 而不是富域对象吗?

于 2009-09-06T13:55:59.123 回答
0

我们都知道Dtos(可能)是什么。 但重要的是是否过度使用 DTO。

在“本地”服务之间传输数据Dtos是一种很好的做法,但会给您的开发团队带来巨大的开销。

有一些事实:

  1. 客户不应看到实体或与实体交互 ( Daos)。因此,您总是需要 Dtos 将数据传输到远程(进程外)/从远程传输数据。
  2. 用于Dtos在服务之间传递数据是可选的。如果您不打算将项目拆分为微服务,则无需这样做。这对你来说只是一个开销。

这是我的评论:如果您打算在不久的将来将您的项目分发到微服务。或者不打算这样做,那么 不要过度使用 DTO

你需要阅读这篇文章https://martinfowler.com/bliki/LocalDTO.html

于 2019-03-23T18:46:59.173 回答