在SOA应用程序中,使用DTO的最佳方式是什么?

7
我们正在使用EF、WCF和jQuery实现一个SOA Web应用程序。
以下是我们的架构简述:
-------------   ---
|    UI     |  |   |
-------------  |   |
| Services  |  | D |
-------------  | T |
| Businsess |  | O |
-------------  |   |
|    Dal    |  |   |
-------------   ---

我们知道在不同层之间传递数据时,特别是在服务和用户界面之间,应使用DTO类。但是我们对如何使用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()

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

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

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

该方法的签名将如下所示:

public List<SampleDTO> GetAllItemsTitle()

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

结论

通常情况下,第一种解决方案(除了手动创建的DTO之外使用POCO)是强类型的。仅需查看方法签名即可找到每个方法返回的数据类型(没有额外的属性)。但是我们担心手动创建的DTO管理问题。它们很快就会增加。

但是第二种解决方案是更加动态的方式,唯一能够识别从“GetAllItemsTitle”返回什么的方法是查看方法体或其文档。因此,我们担心“运行时错误”。开发人员可能认为某个属性不应为空,而实际上却为空。

此外,在我们面临从UI到服务端进行“放置”数据的示例中,我们也遇到了这样的问题。例如,对于更新、插入和其他类似操作,甚至对于“搜索条件”,我们都有相同的选择。

抱歉问题描述得有点长。 请您提供一些有益的建议,谢谢。

3个回答

2
忘记数据层。为每个特定的Web服务调用创建DTO,使其工作。
DTO的构建方式或使用方式并不重要。唯一重要的是如何设计它们以最小化每个操作的Web服务调用量。
例如:假设您有一个用例,需要遍历所有用户以修改他们的地址。糟糕的设计是,您首先需要获取所有用户,然后为每个用户进行一次WebService调用以获取其地址。正确的设计是在单个调用中返回UserWithAddress DTO列表。

好主意,我们会关注它。但现在你推荐我们的解决方案中哪一个?当然,我认为我们应该允许自己创建任意数量的DTO。对吧? - Amir Karimi
从构建服务API开始。所需的DTO数量应在该过程中出现。 - jgauffin
我不知道你是否认真对待你的对象,但通常查看现有内容总是一个好习惯。你的DTO实际上与字典对象的NameValuePair相同。 - Mickey Perlstein

1
那么对于大型项目中的大量DTO,我们应该如何管理呢?你的意思是我们应该为每个UserInfo组合(例如UserWithAddress、UserWithAddressAndAge、UserWithAge、UserWithPhoneNumber和UserWithBlahBlahBlah)都有一个DTO吗?这在大型领域中会很混乱,难以管理和维护。我真的更喜欢可空DTO。
你应该为从现实世界映射的每个对象拥有单独的DTO。业务责任是指定它应该如何使用。一旦你创建了DTO,然后根据你的业务使用它。调用GetUserAddress服务时,不要期望UserAge或任何其他东西。对于用户,我们将其映射到面向对象的User,在设计中只有一个DTO。
还有一件事!如果我们为我们接收的每个单个目的和数据组合创建DTO,作为最近加入支持团队的开发人员,我怎么找到所需的DTO来完成我的新方法呢?我应该搜索所有DTO并小心选择正确的(如果我变成一个懒惰和粗心的开发人员会发生什么?)。也许我应该阅读像“项目的DTO!”这样的文档书籍,以熟悉可用的DTO。

1

DTO(数据传输对象)应根据需要映射到请求或基于能力。您可以聚合各种底层数据实体并返回组合或类似外观的DTO,也可以返回贫血DTO,该DTO仅表示单个数据实体的一小部分。在做出此决策时,您希望平衡有效载荷、粒度和其他SOA问题。

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


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