【问题标题】:What is the best way of using DTOs in a SOA application?在 SOA 应用程序中使用 DTO 的最佳方式是什么?
【发布时间】:2011-08-19 10:03:01
【问题描述】:

我们正在使用 EF、WCF 和 jQuery 实现 SOA Web 应用程序。

这是我们架构的简要视图:

-------------   ---
|    UI     |  |   |
-------------  |   |
| Services  |  | D |
-------------  | T |
| Businsess |  | O |
-------------  |   |
|    Dal    |  |   |
-------------   ---

我们知道我们应该有 DTO 类在层之间特别是在服务和 UI 之间传递数据,但是我们在使用 DTO 的方式(发送到 UI 或从 UI 接收)方面存在一些概念性问题。

对于数据驱动项目,我们可以使用 POCO 自动生成 DTO 对象。但在大型应用程序中,它并不是那么简单。

我们知道解决我们问题的两种解决方案:

第一个解决方案(除了手动创建的新 DTO 之外还使用 POCO)

例如,假设我们有一个包含许多字段的实体。并且有一个显示实体记录的查找组合框。我们只需要一个实体键作为组合框值字段,另一个字段(例如标题)作为组合框文本字段。因此,我们创建了一个名为“GetAllItemsTitle”的方法来检索所有实体。现在我们应该只返回我们想要的结构(在这个例子中是一个键和一个值)。所以我们必须创建一个新类来存储该结构(一个键和一个值)。

这将是新的 DTO 类:

[DataContract]
public class SampleManuallyDto
{
    [DataMember]
    public long Id { get; set; }

    [DataMember]
    public string Title { get; set; }
}

并且方法签名是这样的:

public List<SampleManuallyDto> GetAllItemsTitle()

第二种解决方案(使用 Nullable 或 Emptyable DTO)

我们可以绕过 POCO 并手动创建 DTO。然后我们可以将 DTO 的所有属性定义为可为空的或类似可以被识别为 Empty 的属性(我称之为 Emptyable)。它允许我们将 DTO 用于多种目的。当然我们需要遵循适配器模式。例如,为那些名为“FromEntity”和“ToEntity”的 Emptyable DTO 创建两个方法,将我们手动创建的 DTO 转换为(实体框架的)EntityObjects。

现在我们可以绕过“第一个解决方案”(GetAllItemsTitle)示例中创建新的 DTO 类。

方法签名是这样的:

public List<SampleDTO> GetAllItemsTitle()

但是在方法体中我们只填充了 SampleDTO 的“Id”和“Title”属性。正如我所说,SampleDTO 的所有属性都可以为空,因此我们只需填充我们想要的属性,而将其他属性留空。

结论

通常,第一个解决方案(除了手动创建的新 DTO 之外还使用 POCO)是 Strongy-Typed。只需查看方法签名(没有额外的属性),就可以简单地找出每个方法返回的数据类型。但是我们担心管理手动创建的 DTO。他们很快就会长大。

但第二种解决方案是一种更动态的方式,识别从“GetAllItemsTitle”返回的内容的唯一方法是查看方法主体或其文档。所以我们担心“运行时错误”。开发人员可能会假设属性为空时不应为空。

此外,我们在将数据从 UI 中“放入”服务时遇到此类问题的表达示例。例如对于更新和插入以及其他此类操作。即使是“搜索条件”,我们也有相同的选择。

抱歉,问题太长了。 请帮助我们提出您的善意建议。

【问题讨论】:

    标签: wcf architecture entity-framework-4 poco dto


    【解决方案1】:

    忘记所有关于数据层的事情。创建适用于每个特定 Web 服务调用的 DTO:s。

    DTO 如何构建或如何使用并不重要。唯一重要的是如何设计它们以最大程度地减少每个操作的 Web 服务调用量。

    例如:假设您有一个用例,您需要遍历所有用户来修改他们的地址。如果您首先需要获取所有用户,然后为每个用户进行 Web 服务调用以获取其地址,那么一个糟糕的设计将是一个糟糕的设计。正确的设计是在一次调用中返回UserWithAddress DTO:s 的列表。

    【讨论】:

    • 好主意,我们会关心的。但是现在您推荐我们的哪一种解决方案?当然,我认为我们应该允许自己创建任意数量的 DTO。对吗?
    • 从构建服务 API 开始。在该过程中应该出现所需的 DTO 数量。
    • 我不知道你是否对你的对象很认真,但总的来说,看看存在的东西总是一个好习惯。您的 DTO 实际上与 Dictionary 对象的 NameValuePair 相同。
    【解决方案2】:

    那么我们如何管理大型项目的大量 DTO?你的意思是我们应该为 UserInfo 的每一个组合都有一个 DTO,例如 UserWithAddress、UserWithAddressAndAge、UserWithAge、UserWithPhoneNumber、UserWithBlahBlahBlah?这在大型域中将是一团糟,并且难以管理和维护。我真的更喜欢 Nullable DTO。 对于从现实世界映射的每个对象,您应该有一个 Dto。这是指定如何使用它的商业责任。一旦你创建了一个 Dto,然后根据你的业务使用它。调用 GetUserAddress 服务,不要指望 UserAge 或任何其他东西。当我们在设计中将用户映射到面向对象的用户时,用户只有一个 DTO。

    还有一件事!如果我们为我们收到的每个单一目的和数据服务组合创建一个 Dto,作为最近加入支持团队的开发人员,我如何为我的新方法找到所需的 Dto?我应该搜索所有 Dtos 并小心我的正确选择(如果我是一个懒惰和粗心的开发人员会发生什么?)也许我应该阅读一本文档书,比如“项目的 DTOS!”熟悉可用的 DTO。

    【讨论】:

      【解决方案3】:

      DTO 应根据需要映射到请求或能力。您可以聚合各种底层数据实体并返回复合的或类似外观的 DTO,或者您可以返回仅代表单个数据实体的一小部分的贫乏的 DTO。在做出此决定时,您希望平衡有效负载、粒度和其他 SOA 问题。

      http://www.soapatterns.org/entity_abstraction.php

      【讨论】:

        猜你喜欢
        • 2012-03-06
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-08-05
        • 2018-10-09
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多