当前位置: 首页 > 知识库问答 >
问题:

带EF Core的DDD(DTO、Business等)

朱兴学
2023-03-14

我正在尝试进入设计模式和REST API,对于一个项目,我使用实体框架核心:

  • 存储库模式
  • 工作单位

有些事情对我来说真的很模糊:

  • 数据验证,应该在哪里进行?
  • 事件?这应该在哪里触发?例如:当用户注册时,我想给他们发一封电子邮件。
  • 业务层应该采用DTO还是Domain模型?
  • 从DTO到域模型的转换应该去哪里?
  • 什么应该进入控制器?

我知道这些事情也取决于开发人员,但是最好的/“原创”方式是什么。

共有2个答案

冀嘉木
2023-03-14

数据验证:

所有验证都应该作为域层的一部分执行,通常作为实体类中工厂方法的一部分。如果这更适合您,您可以有一个单独的工厂方法或类。需要记住的关键是:实体/聚合对象应该始终有效。它们不能处于无效状态,需要您使用is\u valid方法检查其有效性。

示例工作流如下所示:

  • 应用程序服务初始化存储库
  • 应用程序服务调用工厂方法来组装实体
  • Factory方法运行验证并确保传递的数据有效
  • Factory方法返回构造的有效对象
  • 应用程序服务将对象传递到要持久化的存储库

活动:

事件应作为域层的一部分在执行业务逻辑后立即触发。

为了防止过早地调度事件(比如说,在数据持久化之前),理想情况下应该在业务逻辑中引发事件,但只有在成功的持久化事务之后,才将它们作为工作单元的一部分进行调度。

DTO处理:

业务层应该接受DTO和返回域模型。验证发生在DTO到域模型的转换过程中。DTO(甚至是普通的关键字参数)是工厂方法的正确输入。

如果所构造的对象是新的,那么从DTO到域模型的转换应该在工厂方法中进行。在处理更新场景的情况下,存储库将获取持久化对象,使用实体的构造函数将其重建为域实体,并在显式update方法中应用DTO更改,该方法还将运行验证。

控制员职责:

控制员应负责:

  • 解构请求对象
  • 正在组装参数(甚至与会话相关的项目,如当前登录的用户
  • 初始化DTO
  • 调用适当的应用程序服务以执行

这些概念适用于任何DDD设计,包括EF Core。

谢华彩
2023-03-14

我需要提前道歉,我可能没有给你足够的食谱,但这是我对你的问题的看法。

您提到了设计模式,但您也用域驱动设计标记了您的问题,所以我假设您的意思是在项目中使用DDD战术模式。我想强调的是,DDD不是一组设计模式,也不是一种设计模式或体系结构风格,它是系统设计时考虑到业务的方式。

在DDD中,最有用的模式之一是聚合模式。集合是形成一致性边界的一组实体,它拥有足够的信息来自行做出任何业务决策,假设该组实体的所有业务规则都聚集在一个地方。

当我们观察事物的应用程序端时,我们通常使用应用程序服务来检索聚合状态,调用聚合根上的一个或多个方法,并将新状态保留回来。重要的是要认识到,所有这些都发生在一次成功、一次交易中,因此工作单元模式间接地应用于此。我之所以这样写,是因为聚合本身就是事务边界,应用程序执行的一个命令就是工作单元。聚合持久性可以使用存储库模式来完成,这就是我们所说的实现细节。

现在,我将尝试解构你的具体观点。

数据验证,应该在哪里进行?

我倾向于将验证视为确保应用程序从外部接收的命令在某种程度上是有效的。这涉及到控制所需的命令字段不为空,并且包含正确的值类型,就像您不能为数字字段发送信函,而电子邮件字段确实包含看起来像有效电子邮件的内容一样。您可以实现多个验证层,使最明显的验证层与客户端保持更近的距离,以便您的用户快速获得反馈。这些简单的检查可以在UI端执行,也可以在边缘执行(在您的例子中是RESTAPI)。

当该命令传递给应用程序服务时,它需要确保获得正确的域实体(聚合)状态,因此至少可以通过尝试从数据库中获取该实体来检查该实体是否存在。您还可以使用值对象,如电子邮件或地址,并从作为命令属性传递的基本类型构造它们。值对象是将一些业务规则放入其中的最佳位置,通过尝试构建它们,验证将自然发生。

最后一个防御层是您的域模型。从前面的所有步骤中,您可以非常确定您已经有了有效的值对象和有效的域实体。聚合保护其不变量,根据定义,不可能将聚合置于无效状态。我通常不称之为验证。

事件?这应该在哪里触发?例如:当一个用户注册时,我想给他们发一封电子邮件。

如果您谈论的是域事件,而不使用事件源,则必须确保在同一事务中将域事件发布到交付介质。当应用程序发布域事件但无法持久化修改后的实体状态时,应避免这种可能性,反之亦然。当这种故障发生时,整个系统将处于不一致的状态。

业务层应该采用DTO还是Domain模型?

我不完全明白这个问题,但您的业务层是您的域模型。域模型通常由实体、值对象和域服务组成。你调用域模型要求它做一些事情,在这个阶段没有涉及DTO。

从DTO到域模型的转换应该去哪里?

在这个上下文中,我将完全避免使用DTO术语,因为您的实体状态可以被视为DTO、API模型和事件。如果您谈论的是您的API合同,它是一个命令,而不是“转换”,那么您的API从API获取命令并调用您的域模型。

什么应该进入控制器?

API控制器只是应用程序的边缘。API负责传输(HTTP或其他东西)、序列化、身份验证和一些授权问题以及异常处理。它的主要目的是确保API请求看起来合法,并将其传递给应用程序服务。

如果您正在寻找一个使用WebAPI、EF并实现一些战术DDD模式的示例应用程序,那么您可能需要查看Packt repo上的工作示例https://github.com/PacktPublishing/Hands-On-Domain-Driven-Design-with-.NET-Core/tree/master/Chapter09/ef-core

 类似资料:
  • Repository This repository is home to the following .NET Foundation projects. These projects are maintained by Microsoft and licensed under the MIT License. Entity Framework Core Microsoft.Data.Sqlite

  • 开场白 在商业全面数字化的今天,越来越多的企业正在通过数字化转型重塑自我。而 XXOO 将作为基础力量,支持卓越绩效企业规模化地迅速展开数字化业务变革。数字化业务依赖与 数字化员工团队 数字化弹性云平台 数字化洞察力 对于这些企业来说,XXOO 将依托数据分析和移动技术获取实时洞察力,随时随地帮助其互联员工团队掌握更多信息。不仅如此,XXOO 在设计建造时就已添加了安全、可靠、稳定、敏捷和成本效益

  • GNU DDD (Data Display Debuger) 是一个图形化的调试工具,通过对调试命令例如 GDB、DBX、WDB、JDB、XDB 等等命令行工具的封装,提供一个非常友好的调试界面。

  • BUSH (Business Shell) 将 BASH、PHP、GCC 和数据库合并到一个用于快速构建安全,可靠的网站的平台。在ISO标准为基础,它促进代码重用:脚本和模板可以用GCC编译或移植到JVM或网络使用只有轻微的变化第三方工具。它也可以取代一个SQL支持交互式命令外壳庆典,并为通用脚本语言。

  • Business Card Example: How this business card was designed, is explained in this blog post. Requirements Recent TeX installation (tested on a 2017 one) XeLaTeX Font Awesome Fira Sans It is also possib

  • 所以我将通过使用一个例子来解释这个问题,因为它使一切更加具体,希望能减少歧义。 架构非常简单 1微服务 每个微服务都将使用CQRS/ES设计模式,这意味着 每个微服务都有自己的Aggregate映射现实世界问题的域 聚合的状态将从事件存储重建 每个事件都将表示聚合中的状态更改,并将通过消息代理传输到对更改感兴趣的任何服务 每个微服务都将在其自己的域内进行事务处理 每个微服务最终都会与其他域保持一致