DTO:最佳实践

时间:2009-09-06 13:43:37

标签: dto

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

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

这样做的最佳方式是什么,是否有任何样本让我开始这样做?

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

Thrid问题:在编写DTO时,我应该编写多个DTO,每个DTO包含给定域模型的部分数据,以便每个DTO可用于满足特定View的要求,或者DTO是否应包含所有数据那些在相应的模型类中。

7 个答案:

答案 0 :(得分:6)

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

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

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

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

马特

答案 1 :(得分:3)

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

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;}
    ...
 }

我希望在我的视图中显示哪些字段。我在数据库访问代码中获取所有这些字段,因此我不必在视图或控制器代码中使用实体注释。

答案 2 :(得分:1)

我来spring-jdbc进行投影,并使用了DAO图层。有时,现有实体不会涵盖来自DB的所有可能数据。所以我开始使用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

答案 3 :(得分:0)

我将假设您的域模型对象具有主键ID,该ID可能与其来自数据库或商店的ID相对应。

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

希望有所帮助。

我是否可以问你为什么选择在视图中使用DTO而不是富域对象?

答案 4 :(得分:0)

开发DTO的最佳方式

开始开发DTO的方法是了解其唯一目的是将业务实体的数据子集传输到不同的客户端(可以是UI或外部服务)。根据这种理解,您可以为每个客户创建单独的包...并编写您的DTO类。对于映射,您可以编写自己的映射器,定义要传递给工厂的接口,根据创建DTO的实体中的哪些数据来提取DTO对象。您还可以定义要放在实体字段上的注释,但是个人给出了使用的注释数量,我更喜欢接口方式。关于DTO的主要注意事项是,它们也是DTO中的类和数据应该被重用,换句话说,虽然为每个用​​例创建DTO似乎很有诱惑力,但是尝试重用现有的DTO来最小化它。

入门

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

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

答案 5 :(得分:0)

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

在{local}服务之间使用Dtos传输数据是一种好习惯,但是这对开发人员团队造成了巨大的开销。

有一些事实:

  1. 客户不应看到实体(Daos)或与之互动。那么你 始终需要Dto来往/从远程传输数据(过程外)。
  2. 使用Dtos在服务之间传递数据是可选的。如果您不打算将项目拆分为微服务,则无需这样做。这只是您的开销。
  

这是我的评论:如果您打算将项目分发到   微服务长期发展。或不打算这样做,然后   请勿过度使用DTO

您需要阅读本文https://martinfowler.com/bliki/LocalDTO.html

答案 6 :(得分:0)

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

问题2:您可以并且可能应该为主要DTO上的每个域对象创建一个DTO。一个DTO可以在其中包含多个DTO,每个DTO都需要映射一个域对象。并映射它们,您可以自己做,甚至可以使用一些模型映射器。

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

如果需要澄清,只需询问即可。