AutoMapper 模式是不是违反 DDD 原则?
Posted
技术标签:
【中文标题】AutoMapper 模式是不是违反 DDD 原则?【英文标题】:Does AutoMapper pattern violate principle of DDD?AutoMapper 模式是否违反 DDD 原则? 【发布时间】:2020-07-11 18:35:12 【问题描述】:我最近在尝试 Abp 框架,很高兴地发现它是 DDD 的一个很好的实现。但是由于它使用 AutoMapper 将 DTO 转换为实体/聚合,我注意到它能够使我的私有聚合设置器短路,这显然违反了 DDD 的主要规则。虽然 AutoMapper 的目标是减少人工操作,但 DDD 强调通过私有 setter 实现不变性。
怎样才能把这两个看似矛盾的概念搞清楚,并顺利使用这个框架呢?这是否意味着我必须放弃 AutoMapper 才能保留 DDD 原则,反之亦然?
我相信 AutoMapper 不是 DDD 的反模式,因为它在社区中非常流行。换句话说,如果 AutoMapper 可以使用反射(据我所知)来设置私有设置器,那么其他任何人都可以。这是否意味着私有 setter 本质上是不安全的?
感谢任何可以帮助我或给我提示的人。
【问题讨论】:
为什么要将 DTO 转换为实体/聚合? 来自客户的数据总是以 DTO 的形式上传,经过验证后,无论使用什么方法,在持久化之前,它们当然必须转换为实体/聚合。 在这种情况下,翻译行为成为领域模型的实际行为,不可避免地导致领域模型贫乏。如果你问我,就达不到目的。 谢谢,我理解你的建议。我还有一个问题:如果我有一个相对较大的聚合并且它的大部分属性是强制性的,这是否意味着我必须创建一个具有长(而且我看到丑陋)参数列表的构造函数?有什么优雅的方法来处理这个问题吗? 取决于您要解决的问题。但是有很多选择——你可以传入字典,你可以使用构建器/工厂模式。您也可以拆分聚合。 【参考方案1】:如何把这两个看似矛盾的概念搞清楚,并顺利使用这个框架?
通过配置 AutoMapper 的配置文件以使用使用聚合的工厂方法或构造函数的自定义表达式来构造聚合根。这是我的一个项目中的一个示例:
public class BphNomenclatureManagerApplicationAutoMapperProfile : Profile
public BphNomenclatureManagerApplicationAutoMapperProfile()
CreateMap<BphCompany, BphCompanyDto>(MemberList.Destination);
CreateMap<CreateUpdateBphCompanyDto, BphCompany>(MemberList.Destination)
// invariants preserved by use of AR constructor:
.ConstructUsing(dto => new BphCompany(
dto.Id,
dto.BphId,
dto.Name,
dto.VatIdNumber,
dto.TradeRegisterNumber,
dto.IsProducer
));
【讨论】:
【参考方案2】:AutoMapper 是:.NET 中基于约定的对象-对象映射器。
AutoMapper 本身并没有违反 DDD 的原则。可能是你使用它的方式。
如何才能把这两个看似矛盾的概念搞清楚,并顺利使用这个框架呢?这是否意味着我必须放弃 AutoMapper 才能保留 DDD 原则,反之亦然?
不,您不必放弃 AutoMapper。
您可以为每个地图指定.IgnoreAllPropertiesWithAnInaccessibleSetter
。
相关:How to configure AutoMapper to globally Ignore all Properties With Inaccessible Setter(private or protected)?
换句话说,如果 AutoMapper 可以使用反射(据我所知)来设置私有设置器,那么其他任何人都可以。这是否意味着私有 setter 本质上是不安全的?
不,这意味着反射非常强大。
【讨论】:
谢谢,我知道了,没有模式是灵丹妙药。【参考方案3】:对 Abp 框架了解不多。私有设置器只是用于 DDD(封装)的古老传统 OOP。您应该从您的聚合中公开将更改其状态的公共方法。 Automapper 可用于您的应用程序层,您将 DTO 映射到域构建块(如值对象),并将它们作为参数传递到您的聚合公共函数中,这些函数将更改其自身的状态并强制执行不变量。话虽如此,并不是每个人都喜欢 Automapper :)
【讨论】:
问题是,如果反射机制可以使用私有设置器修改属性,那么任何使用我的模块的人都可以(有意或无意地)入侵我的聚合,这是真的吗? @SillyJumper,是的,但这是设计使然。反射需要强大到能够实现一些复杂的用例。好处是你可以控制你的依赖。如果你发现你不喜欢AutoMapper
,因为它会与你的对象混淆,你可以停止使用它。
就像@nova 所说,您可以使用AutoMapper
仅映射没有自身不变量的简单对象,就像大多数值对象一样。您可以手动映射其余部分(即,使用从 DTO 属性获取的参数调用构造函数或工厂方法)。更好的是,您可以将此逻辑放入 Aggregate Root 上的工厂方法中,该方法将 DTO 作为输入以及所需的任何其他内容,然后在应用程序服务中使用该工厂方法来创建有效的 AR 实例,然后坚持它或您的用例正在做什么。以上是关于AutoMapper 模式是不是违反 DDD 原则?的主要内容,如果未能解决你的问题,请参考以下文章