c# - 当有单独的数据模型时,如何从存储库返回域对象?

标签 c# design-patterns domain-driven-design

更新

我的研究告诉我应该使用数据映射器:https://martinfowler.com/eaaCatalog/dataMapper.html .数据映射器是否像这样注入(inject)到存储库中:http://www.rantdriven.com/post/2009/09/01/Using-the-Repository-Pattern-with-the-Command-and-DataMapper-Patterns.aspx还有这个:Repository and Data Mapper pattern还是它们被用作存储库的替代品?我发现的所有示例似乎都使用数据映射器将 DataReader 对象映射到域对象列表。我想将持久对象映射到域对象。

原始问题

在阅读了如下文章后,我正在尝试构建一个与数据模型完全隔离的领域模型: http://blog.sapiensworks.com/post/2012/04/07/Just-Stop-It!-The-Domain-Model-Is-Not-The-Persistence-Model.aspx .目前我们只有六个人在这个系统上工作,但是将来可能会增加到 9+。但是,我开始认为这不是正确的方法。我在这里阅读了很多问题,这些问题似乎告诉我将 ORM 直接映射到域模型。 我最近问了这个问题:https://softwareengineering.stackexchange.com/questions/365643/should-the-data-model-be-identical-to-the-domain-model-for-mapping-purposes .其中一位回答者说:“我相信两者之间的映射应该在一个(面向持久性的)存储库中”。你如何做这个映射?由于此处所述的原因,我认为我不应该在存储库中使用 AutoMapper:Repository pattern and mapping between domain models and Entity Framework在这里:http://enterprisecraftsmanship.com/2016/02/08/specification-pattern-c-implementation/即我不能简单地在存储库中执行此操作:

public Customer getId()
{
   CustomerData customerData = customerRepository.getById(id);
   return Mapper.Map<CustomerDomain>(customerData);
}

我不能这样做,因为不会考虑域对象的不变量。如何从存储库返回域对象。我是否将一个工厂注入(inject)到存储库中,它将从数据模型中获取参数并返回一个域模型?这是否是正确的方法,或者是否存在将数据对象映射到域对象的另一种模式?

最佳答案

按照 Evans 的定义快速查看存储库

REPOSITORIES (provide) the means of finding and retrieving persistent objects while encapsulating the immense infrastructure involved.

(REPOSITORIES) provide the illusion of an in memory collection...

因此,API接口(interface)通常应该用特定领域的词汇来表达;应用层和域模型都不需要知道 API 中表达的内容以外的任何细节。

通常,庞大的基础架构意味着与域无关的持久性设备;我们不持久化域对象,我们持久化字节。对于某些设备,我们与字节表示密切相关——想想流式传输数据到文件和从文件流出数据。在其他情况下,设备提供了这些字节的抽象 - RDBMS 为我们提供了一个 API,可以理解表中的行,并封装了字节排列方式的详细信息。

这意味着某处我们需要从领域不可知的表示到领域特定的表示的转换,反之亦然。

通常,这些采用函数的形式。

toDomainModel: JsonDocument -> DomainModel
toJson: DomainModel -> JsonDocument

这些函数通常由存储库实现定义和调用——它们是 Evans 描述的巨大基础设施的一部分。

I cannot do this because the invariants of the domain object will not be considered.

这里有几种可能性。

当然,其中之一是获得更智能的制图器。

第二种可能性是将模型的未验证表示建模为与已验证表示不同的事物。

示例:考虑一个Money 模型,它需要一个Amount 和一个CurrencyCode;并且您的模型的语义要求 Amount 是一个正数并且 CurrencyCode 是固定标记集合中的一个条目。拥有一个没有语义限制的 UnvalidatedMoney 类型和一个将 UnvalidatedMoney 转换为 Money(强制不变)的函数并没有错。

这类似于 Scott Wlaschin描述了如何为经过验证的电子邮件地址建模。

请注意,这不一定是不当负担;如果您对某些领域概念(例如金钱)有不变性,那么在将来自世界的新输入传递到您的模型时,您可能已经需要进行验证。因此,这项工作主要是关于使该验证元素可重用。

第三种可能性是研究构建器模式。从一个角度来看,持久对象是模型在过去写入的消息,以便将来可以读取它。因此,通常情况下,查看常见的消息传递模式很有用。

在这种方法中,我们将加载一个构建器实例(由工厂为我们创建,由域模型实现),它有一个 API,允许存储库将域不可知数据传递到域模型。同样,由域模型提供的消息生成器知道域不变性并可以对其进行验证。

All the validation for the domain object is done in the constructor. Should I just inject a factory into the repository?

应该没问题。您将希望保持耦合尽可能小(考虑接口(interface)),并且您需要考虑工厂现在是模型公共(public) API 的一部分这一事实(考虑如何更改工厂以便它保持向后兼容)。

关于c# - 当有单独的数据模型时,如何从存储库返回域对象?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48719196/

相关文章:

c# - 多线程 - 等待所有线程收到信号

c# - 序列化: Cannot convert type string[][] to string[]

c# - 如何存储以前的向导页面?

domain-driven-design - DDD : Where should data be converted, 格式化、加密等?

c# - 如何编写使用 return 关键字的单元测试用例?

javascript - jQuery 如何调用一个对象 $

javascript - 我真的需要一个单例吗?

c# - RESTful设计——通过传递列表请求多条记录

domain-driven-design - 强制聚合之间不变量的最佳方法?

.net - CQRS,DDD同步报告数据库