POCO = 简单的旧CLR(或更好:类)对象
DTO = 数据传输对象
在这篇文章中存在差异,但实际上我阅读的大多数博客都将POCO描述为DTO定义的方式:DTO是用于在应用程序的层之间移动数据的简单数据容器。
POCO和DTO是相同的吗?
我已经在我的博客文章中表明了我的立场,因此为我做出贡献可能是多余的,但该文章的最后一段总结了一切:
因此,总之,学会喜欢POCO,并确保您不会传播任何关于它与DTO相同的错误信息。 DTO是用于在应用程序的各个层之间移动数据的简单数据容器。 POCO是完整的业务对象,其唯一要求是持久性无关(没有获取或保存方法)。 最后,如果您还没有查看Jimmy Nilsson的书,请从当地的大学图书馆中获取。 它有C#示例,是一本很棒的读物。
顺便说一句,Patrick,我把POCO作为生活方式文章阅读了一遍,我完全同意,那是一篇很棒的文章。 实际上,它是我推荐的Jimmy Nilsson书中的一节。 我不知道它可以在线获得。 他的书确实是我发现的有关POCO / DTO / Repository和其他DDD开发实践的最佳信息来源。
POCO是一个不依赖于外部框架的简单对象。它是“纯”的。
一个POCO是否有行为是无关紧要的。
DTO可能是POCO,领域对象也可能是POCO(通常富含行为)。
通常DTO更可能依赖于外部框架(例如属性)进行序列化,因为它们通常存在于系统边界处。
在典型的洋葱式架构(通常在广泛使用的DDD方法中使用),领域层位于中心位置,因此其对象在此阶段不应具有领域层以外的依赖关系。
我为这个主题写了一篇文章:DTO vs Value Object vs POCO。
简而言之:
DTO描述了状态传输的模式。POCO除了没有特殊之外,几乎什么都不描述。这是面向对象编程中“对象”的另一种说法。它来自于POJO(Java),由Martin Fowler创造,他只是将其描述为“对象”的一个更高级的名称,因为“对象”并不太吸引人,人们对此避而远之。
好吧,为了解释这个问题,我从未想过需要用更高深的方式来解释,从你关于DTO的最初问题开始:
DTO是一种用于在关注点层之间传输状态的对象模式。它们可以具有行为(也就是可以是POCO),只要该行为不改变状态。例如,它可能有一个将自身序列化的方法。为了成为一个合适的DTO,它需要是一个简单的属性包;必须清楚地表明这个对象不是一个强大的模型,它没有暗示的语义含义,并且不强制执行任何形式的业务规则或不变量。它只是存在于数据传输中。
POCO是一个普通对象,但所谓“普通”是指它没有特殊要求或约定。它只是意味着它是一个没有隐含模式的CLR对象。一个通用的术语。我还听说它被扩展为描述它也不是为了与其他框架一起使用而制作的。因此,如果你的POCO在其属性上有大量的EF装饰,例如,那么我会认为它不是一个简单的POCO,而更多地属于DAO领域,我将其描述为DTO和额外的数据库关注点(例如映射等)的组合。POCOs像你在学校里学习创建的对象一样自由而无拘束。所以如果你告诉我某个东西是 DTO,那么我很可能会确保它只用于传递状态。如果你告诉我某个东西是视图模型,那么我很可能会确保它不会保存到数据库,并且知道可以在其中放入一些“hacky”的东西,以确保数据可供 UI 使用。如果你告诉我某个东西是领域模型,那么我很可能会确保它不依赖于领域之外的任何东西,尤其是不依赖于任何技术实现细节(数据库、服务等),只能依赖于抽象。但如果你告诉我某个东西是 POCO,除了告诉我它不应该被检测和操作之外,实际上并没有提供太多信息。
这是一个简单但准确的示例,应该很容易理解。
这个对象可能是 POCO,也可能是 DTO。它只是一个对象,没有什么特殊之处。看起来像是弱类型的属性包,但没有什么值得注意的地方。
public class CreateUserRequest
{
public string Name { get; set; }
public string Email { get; set; }
}
public class CreateUserRequest
{
[JsonPropertyName(Name = "name")]
public string Name { get; set; }
[JsonPropertyName(Name = "email")]
public string Email { get; set; }
}
[Table("Users")]
public class CreateUserRequest
{
[Key]
[JsonIgnore]
public string Id { get; set; }
[JsonPropertyName(Name = "name")]
public string Name { get; set; }
[JsonPropertyName(Name = "email")]
public string Email { get; set; }
public int LoginCount { get; set; }
public void IncrementLogin() => LoginCount++;
}
LoginCount
是要成为JSON合同还是数据库模式的一部分。这是一个普遍的规则:DTO==有害,是过度工程化软件的指示器。POCO==好。"企业级"模式已经毁掉了很多Java EE世界中人们的思维。请不要在.NET领域重蹈覆辙。
甚至不要称它们为DTO。它们被称为模型......就是这样。模型从不具有行为。我不知道是谁想出了这个愚蠢的DTO术语,但我想这一定是.NET的事情。在MVC中考虑视图模型,同样的东西,模型用于在服务器端或通过网络传输状态,它们都是模型。带有数据的属性。这些是您通过网络传递的模型。模型,模型,模型。就是这样。
我希望愚蠢的DTO术语能够从我们的词汇表中消失。