如何在业务逻辑层设计数据传输对象
Posted
技术标签:
【中文标题】如何在业务逻辑层设计数据传输对象【英文标题】:How to Design Data Transfer Objects in Business Logic Layer 【发布时间】:2010-10-09 03:21:00 【问题描述】:DTO
我正在构建一个希望扩展到许多用户的 Web 应用程序。此外,我需要通过 Web 服务向受信任的第三方公开功能。
我正在使用 LLBLGen 生成数据访问层(使用 SQL Server 2008)。目标是构建一个业务逻辑层,将 Web 应用程序与 DAL 的细节隔离开来,当然,还提供 DAL 之外的额外验证级别。此外,据我现在所知,Web 服务本质上将是 BLL 的薄包装器。
当然,DAL 有自己的一组实体对象,例如 CustomerEntity、ProductEntity 等等。但是,我不希望表示层直接访问这些对象,因为它们包含特定于 DAL 的方法,并且程序集特定于 DAL 等等。因此,这个想法是创建数据传输对象 (DTO)。这个想法是,本质上,这些将是普通的旧 C#/.NET 对象,它们具有所有字段,例如 CustomerEntity,实际上是数据库表 Customer,但没有其他东西,除了一些 IsChanged/IsDirty 属性。因此,会有 CustomerDTO、ProductDTO 等。我假设这些将继承自基本 DTO 类。我相信我可以使用 LLBLGen 的一些模板生成这些,但我还不确定。
因此,BLL 将通过接受和返回这些 DTO 对象来公开其功能。我认为 Web 服务将处理将这些对象转换为 XML 以供使用它的第三方使用,许多可能不使用 .NET(此外,有些东西将是可从 Web 应用程序上的 AJAX 调用使用 JSON 调用的脚本)。
我不确定设计这个的最佳方式以及如何继续前进。以下是一些问题:
1) 这应该如何暴露给客户端(表示层和 Web 服务代码)
我在想会有一个拥有这些方法的公共类,每次调用都是原子操作:
InsertDTO、UpdateDTO、DeleteDTO、GetProducts、GetProductByCustomer 等等...
然后客户端只需调用这些方法并传入适当的参数,通常是 DTO。
这是一个好的、可行的方法吗?
2) 从这些方法返回什么?显然,Get/Fetch 类型的方法将返回 DTO。但是插入呢?部分签名可能是:
InsertDTO(DTO dto)
但是,插入的时候应该返回什么?我想收到错误通知。但是,我对某些表使用自增主键(但是,一些表具有自然键,尤其是多对多表)。
我想到的一个选项是 Result 类:
class Result
public Exception Error get; set;
public DTO AffectedObject get; set;
因此,在插入时,DTO 将获取其获取 ID(如 CustomerDTO.CustomerID)属性集,然后放入此结果对象。如果 Result.Error != null 客户端会知道是否有错误,然后它会从 Result.AffectedObject 属性中知道 ID。
这是一个好方法吗?一个问题是,它似乎在来回传递大量冗余数据(当它只是 ID 时)。我不认为添加“int NewID”属性是干净的,因为某些插入不会有这样的自动递增键。另一个问题是我认为 Web 服务不能很好地处理这个问题?我相信他们只会在 Result 类中返回 AffectedObject 的基本 DTO,而不是派生的 DTO。我想我可以通过拥有大量不同类型的 Result 对象(可能从基本 Result 派生并继承 Error 属性)来解决这个问题,但这似乎不是很干净。
好吧,我希望这不是太罗嗦,但我想清楚。
【问题讨论】:
【参考方案1】:1:这是一种非常标准的方法,非常适合“存储库”实现,以获得最佳的可单元测试方法。
2:异常(应该在 WCF 边界上声明为“故障”,顺便说一句)将自动引发。你不需要直接处理。对于数据 - 有三种常用方法:
在合约上使用ref
(不是很漂亮)
返回(更新的)对象 - 即public DTO SomeOperation(DTO item);
只返回更新后的身份信息(主键/时间戳等)
关于所有这些的一件事是,它不需要每个操作使用不同的类型(对比您的 Result
类,它需要每个 DTO 复制)。
【讨论】:
【参考方案2】:Q1:您可以将 WCF 数据协定复合类型视为解决此问题的 DTO。这样,您的 UI 层只能访问 DataContract 的 DataMember 属性。您的原子操作将是 WCF 接口公开的方法。
Q2:配置您的响应数据协定以使用您的主键等返回一个新的自定义类型... WCF 也可以配置为将异常返回到 UI。
【讨论】:
以上是关于如何在业务逻辑层设计数据传输对象的主要内容,如果未能解决你的问题,请参考以下文章