4.7 Data transfer Objects 数据传输对象

Data transfer Objects 数据传输对象

A DTO is a simple object that is used to transfer state (data) between the Application and Presentation Layers. So,Application Service methods gets and returns DTOs.

DTO是一个简单的对象,用于在应用层和表现层之间传输状态(数据)。因此,应用服务方法获取和返回DTO。

Common DTO Principles & Best Practices DTO一般原则和最佳实践

  • A DTO should be serializable, by its nature. Because,most of the time it is transferred over network. So, it should have a parameterless (empty) constructor.
  • 从本质上讲,DTO应该是可序列化的。因为,大部分时间它都是通过网络传输的。所以,它应该有一个无参数(空)构造函数
  • Should not contain any business logic.
  • 不应该包含任何业务逻辑
  • Never inherit from or reference to entities.
  • 永远不要继承或引用实体

Input DTOs (those are passed to the Application Service methods) have different natures than Output DTOs (those are returned from the Application Service methods). So, they will be treated differently.

输入DTO(指那些被传递给应用服务方法的DTO)与输出DTO(指那些从应用服务方法返回的DTO)有本质上的差异。因此,它们将被区别对待。

Input DTO Best Practices 输入DTO最佳实践

Do not Define Unused Properties for Input DTOs 不要为输入DTO定义无用的属性

Define only the properties needed for the use case! Otherwise,it will be confusing for the clients to use the Application Service method. You can surely define optional properties, but they should effect how the use case is working, when the client provides them.

只定义用例所需的属性! 否则,客户端在使用应用服务方法时就会感到困惑。你当然可以定义可选的属性,但当客户端提供这些属性时,它们可能会影响用例的工作方式。

This rule seems unnecessary first. Who would define unused parameters (input DTO properties) for a method? But it happens, especially when you try to reuse input DTOs.

这条规则首先似乎没有必要。谁会为一个方法定义未使用的参数(输入DTO属性)?但这种情况经常发生,特别是当你试图重用输入DTO的时候。

Do not Re-Use Input DTOs 不要重复使用输入DTO

Define a specialized input DTO for each use case (Application Service method). Otherwise, some properties are not used in some cases and this violates the rule defined above: Do not Define Unused Properties for Input DTOs.

为每个用例(应用服务方法)定义一个特有的输入DTO。否则,一些属性在某些情况下不会被使用,这就违反了上面定义的规则:不要为输入DTO定义无用的属性。

Sometimes, it seems appealing to reuse the same DTO class for two use cases, because they are almost same. Even if they are same now, they will probably become different by the time and you will come to the same problem. Code duplication is a better practice than coupling use cases.

有时,在两个用例中重复使用同一个DTO类似乎很有吸引力,因为它们几乎是一样的。即使它们现在是一样的,随着时间的变化它们可能会变得不同,你会遇到同样的问题。重复代码与用例耦合相比来说是一种更好的做法。

Another way of reusing input DTOs is inheriting DTOs from each other. While this can be useful in some rare cases, most of the time it brings you to the same point.

重用输入DTO的另一种方式是相互继承DTO。虽然这在某些罕见的情况下是有用的,但大多数时候它带给你的是同样的问题。

Example: User Application Service 示例:用户应用服务

4.7 Data transfer Objects 数据传输对象

IUserAppService uses UserDto as the input DTO in all methods (use cases). UserDto is defined below:

IUserAppService在所有方法(用例)中使用UserDto作为输入DTO。UserDto定义如下:

4.7 Data transfer Objects 数据传输对象

For this example; 就这个例子而言:

  • Id is not used in Create since the server determines it.
  • Id在Create方法中没有使用,因为它由服务端生成。
  • Password is not used in Update since we have another method for it.
  • Password在更新中没有使用,因为我们修改密码用另一种方法。
  • CreationTime is never used since we can't allow client to send the Creation Time. It should be set in the server.
  • CreationTime从来都不会用到,因为我们不允许客户端发送创建时间。它应该在服务端中设置。

A true implementation can be like that: 真正的实现可以是这样的:

4.7 Data transfer Objects 数据传输对象

With the given input DTO classes: 用到的输入DTO类:

4.7 Data transfer Objects 数据传输对象

This is more maintainable approach although more code is written.

这是更便于维护的方法,尽管要写更多的代码。

Exceptional Case: There can be some exceptions for this rule: If you always want to develop two methods in parallel, they may share the same input DTO (by inheritance or direct reuse). For example, if you have a reporting page that has some filters and you have multiple Application Service methods (like screen report, excel report and csv report methods) use the same filters but returns different results, you may want to reuse the same filter input DTO to couple these use cases. Because, in this example, whenever you change a filter, you have to make the necessary changes in all the methods to have a consistent reporting system.

例外情况:这条规则也可能有一些例外:如果你总是想并行开发两个方法,它们可能共享相同的输入DTO(通过继承或直接重用)。例如,如果你有一个有一些过滤条件的报表页面,你有多个应用服务方法(如显示屏看板、excel报表和csv报表方法)使用相同的过滤条件,但返回不同的结果,你可能想重用相同的带过滤条件输入DTO来复用这些用例。因为,在这个例子中,每当你改变一个过滤条件时,你必须在所有的方法中进行必要的改变,以拥有一个一致的报表系统。

Input DTO Validation Logic 输入DTO校验逻辑

  • Implement only formal validation inside the DTO. Use Data Annotation Validation Attributes or implement IValidatableObject for formal validation.
  • 在DTO内部只实现表象验证。使用数据注解验证属性或实现IValidatableObject进行表象验证。
  • Do not perform domain validation. For example, don't try to check unique username constraint in the DTOs.
  • 不要进行领域验证。例如,不要试图在DTO中检查唯一的用户名约束。
Example: Using Data Annotation Attributes 示例:使用数据注解属性

4.7 Data transfer Objects 数据传输对象

ABP Framework automatically validates input DTOs, throws AbpValidationException and returns HTTP Status 400 to the client in case of an invalid input.

ABP框架自动验证输入的DTO,抛出AbpValidationException,并在输入无效的情况下向客户端返回HTTP状态码400

Some developers think it is better to separate the validation rules and DTO classes. We think the declarative (Data Annotation) approach is practical and useful and doesn't cause any design problem. However, ABP also supports FluentValidation integration if you prefer the other approach.

一些开发者认为将验证规则和DTO类分开更好。我们认为声明式(Data Annotation)的方法是实用的的和有用的,不会引起任何设计问题。然而,如果你喜欢其他的方法,ABP也支持FluentValidation集成。

See the Validation document for all validation options.

想了解所有验证选项参见验证文档。

Output DTO Best Practices 输出DTO的最佳实践

  • Keep output DTO count minimum. Reuse where possible (exception: Do not reuse input DTOs as output DTOs).
  • Output DTOs can contain more properties than used in the client code.
  • Return entity DTO from Create and Update methods.

The main goals of these suggestions are;

上一篇:objects as points


下一篇:objects类