【发布时间】:2019-06-26 18:38:11
【问题描述】:
我正在建立一个应用洋葱架构和 DDD 模式的解决方案。
DDD 原则之一鼓励域实体仅具有私有设置器和私有默认构造函数,以确保您无法在无效状态下创建域实体。
存储库包含域实体上的数据操作,这些操作从/映射到数据库。我一直在尝试以下两种方法:
以纯粹方式的域实体:没有默认构造函数,没有公共设置器;验证在构造函数中完成;这确保您不能在无效状态下创建域实体。副作用是在读操作中更难在存储库中将它们非实体化;因为您需要反射才能创建实例和映射属性;以及在需要映射到实际域实体的 Dapper 请求中使用动态。如果我不使用动态将其直接映射到域实体,Dapper 会抛出没有公共构造函数的异常。
以非纯粹方式的域实体:您允许默认构造函数,并且所有 setter 都是公共的;因此您可以创建在给定时间点无效的实体。在这种情况下,您需要手动调用 Validate() 方法,以确保它们在继续之前有效。这使得存储库中的去材料化变得更加容易,因为您不需要反射或动态来将数据库映射到模型。
这两种方法都有效,但是,使用选项 2,存储库变得更加简单,因为它们包含的自定义映射代码要少得多,而且没有反射显然也会提高性能。当然,DDD 并不是以纯粹的方式应用的。
在决定我将在我的项目中使用什么之前,有一个问题:是否有任何其他 micro-ORM 框架可以处理私有构造函数和设置器,以便将数据库映射到这些类型在没有额外的自定义映射逻辑的情况下支持“纯”域实体? (没有 EF 也没有 NHibernate,我想要一些轻量级的东西)。
或其他技术解决方案来保持“纯”模型实体方法与简单的存储库映射相结合?
编辑:我实施的解决方案如下。
首先,域实体中的构造函数和设置器都是“内部”的,这意味着它们不能由域模型的消费者设置。但是,我使用“InternalsVisibleTo”来允许数据访问层直接访问它们,因此这意味着使用 Dapper 从数据库中去实体化非常容易(不需要中间模型)。从应用层来说,我只能用领域方法来改变领域实体,不能直接改变属性。
其次,为了从我的应用层构建新的域实体,我添加了流畅的构建器来帮助构建域实体,所以我现在可以像这样构建它们:
User user = new UserBuilder()
.WithSubjectId("045454857451245")
.WithDisplayName("Bobby Vinton")
.WithLinkedAccount("Facebook", la => la.WithProviderSubjectId("1548787788877").WithEmailAddress("bobby1@gmail.com"))
.WithLinkedAccount("Microsoft", la => la.WithProviderSubjectId("54546545646").WithEmailAddress("bobby2@gmail.com"))
当构建器“构建”实体时,验证也会完成,因此您永远不能创建处于无效状态的实体。
【问题讨论】:
-
你会选择什么,为什么?,还有其他的吗...? Are not valid questions on stackoverflow
标签: c# architecture domain-driven-design dapper