[英]DDD Accessing an Entity by an indirect parent Entity Id
我正在构建一个集成Plaid API的应用程序以访问用户银行信息(登录、帐户、交易等)。 我正在尝试遵循 DDD 原则。
以下是 Plaid API 流程如何工作的一般概念:
到目前为止,我在我的域层中创建了 3 个实体:项目、帐户和交易。 我为每个创建了一个包含基本 CRUD 操作的存储库。
public class Item
{
public string Id { get; set; }
public string AccessToken { get; set; }
public string UserId { get; set; }
...
}
public class Account
{
public string Id { get; set; }
public string ItemId { get; set;
...
}
public class Transaction
{
public string Id { get; set; }
public string AccountId { get; set;
...
}
可以看到,这些实体之间的关系是:
用户拥有物品-> 物品拥有账户-> 账户拥有交易
我的问题是,当我需要通过间接父项查找实体时会发生什么? 例如: GetTransactionsByItemId或GetAccountsByUserId 。 基于DDD,这个逻辑go应该放在哪里?
由于我的数据结构(1-多关系的非 SQL 链),我知道我必须分多个步骤进行此类查询。 但是,我读到 Repository 应该只关心它自己的实体,所以我怀疑将 ItemsRepository 和 AccountsRepository 注入 TransactionsRepository 以添加GetTransactionsByItemId方法可能不是一个好主意。
我还阅读了有关将许多存储库注入服务并从内部管理所有这些“连接”的信息。 但是,我无法为该服务想出一个名称,所以我担心那是因为从概念上讲这没有多大意义。
我还阅读了有关聚合的信息,但我不确定我是否识别出这些实体中的根。
我能想到的另一种选择是尝试通过向每个事务添加 ItemId 来缩短关系。 但是,由于我是如何从 api 获取数据的,所以这需要破解。
我会说你的聚合根将是一个项目。 如果我的结构正确,则没有帐户就不能存在没有项目和交易的帐户。 所以你可以只使用 ItemsRepository:
public class ItemsRepository
{
public async Task<Item> GetById(long id, IncludesSpec includes)
{
return await this.context.Items
.Where(c => c.Id == id)
.Include(c => c.Accounts).ThenInclude(c => c.Transactions)
.SingleOrDefaultAsync();
}
}
比你得到一个包含所有加载数据的项目。 IncludesSpec 由您决定:它将包含应该制作的包含内容,以及应在存储库方法中动态添加的包含内容。
从 .net ef core 5 开始,您可以执行过滤包含,如.Include(c => c.Accounts.Where(...)),因此您可以根据您的要求进一步缩小实际包含范围。 您可以传递另一个包含此过滤器信息的参数。
此外,您的项目应将 Accounts 公开为只读集合(使用 EF 的支持字段)并提供方法 AddAccount() 以便没有人可以将您的 DDD 项目修改为纯实体。
我认为,最有意义的是拥有一个注入多个存储库的服务。
您可以有一个返回Item
对象的ItemRepository
,一个返回Account
的AccountRepository
,一个返回TransactionRepository
的Transaction
和一个返回User
的UserRepository
。
如果您的数据 model 使得在一个请求中执行查询变得很麻烦,那么在您的服务中有一个 function 是事务性的(ACID:要么全部完成要么全部回滚)它对每个注入的存储库执行不同的查询,然后构建对象并返回它们。
如果您确实看到了一种使其成为一个查询的方法,则可以在相关存储库中对该查询进行硬编码。 来自领域驱动设计,埃文斯:
硬编码查询可以构建在任何基础设施之上,无需大量投资,因为它们所做的正是某些客户无论如何都必须做的事情。
在有大量查询的项目上,可以构建一个 REPOSITORY 框架,允许更灵活的查询。[...]
通过框架概括 REPOSITORIES 的一种特别合适的方法是使用基于 SPECIFICATION 的查询。 SPECIFICATION 允许客户描述(即指定)想要什么,而不用关心如何获得它。 在此过程中,创建了一个可以实际执行选择的 object。 [...]
即使是具有灵活查询的 REPOSITORY 设计也应该允许添加专门的硬编码查询。 它们可能是封装常用查询或不返回对象本身的查询的便捷方法,例如所选对象的数学摘要。 不允许此类意外事件的框架往往会扭曲域设计或被开发人员绕过。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.