DDD:映射到具有大量数据库列的表的实体

use*_*300 5 c# entities domain-driven-design

我尝试遵循 DDD 方法来构造实体,其中属性具有私有 setter 和公共 getter,并且通过构造函数完成赋值。这种方法的问题似乎是,当您遇到一个包含很多列的表时,我们有一个至少有 40 列的表。它很快就会变成一场噩梦。我发现一些文章似乎指向流畅的接口或工厂模式。看起来有 40 列,但即使使用这些模式,cleaner 仍然可能会失控。这些列与表设计相关,并且不违反 SRP。此外,在尝试维持表大小并可能根据逻辑分组将实体分解为较小的值对象时,某些值对象似乎仍然很大。有人能给我指出如何在不破坏 DDD 的情况下处理这种情况的正确方向吗?

Eug*_*ène 2

这并不是说 DDD 不适合宽列。隐藏 setter 也不是 DDD 的特定要求,而是普通的旧封装。(保护数据的修改。)如果您必须设置很多这些值并且发现自己混淆了代码,那么是的,正如您提到的,将构造移至工厂。

当然,秘诀是不要让任何消费代码只是将任何值分配给您的域对象,而不遵循正确的“域逻辑”,因此隐藏了设置器。当然,有时您必须将所有这些值设置为域对象,并且这些值来自某些 dto 或 mvc 模型或其他东西,然后使用可以映射/分配值的 Mapper 类是保持使用代码干净的好方法。

您甚至可以考虑使用 Jimmy Bogard 的 AutoMapper 之类的东西:http://automapper.org/,顺便说一下,它也可以毫无问题地将值分配给私有设置器。

如果您使用 ORM 加载数据,其中一些支持私有设置器和/或支持字段。例如,NHibernate 在您的映射文件中允许这样做:

this.Property(x => x.Description, mapper => mapper.Access(Accessor.Field))
Run Code Online (Sandbox Code Playgroud)

根据我的评论,使用 AutoMapper 之类的东西来减轻大量映射代码的编写。将实现包装在可注入类中,如下所示,这将允许您将来替换实现,而无需执行霰弹枪手术。

public class ViewMapper<TModel, TDomain> : IViewMapper<TModel, TDomain>
{
    public TDomain MapToDomain(TModel dataItem)
    {
        return Mapper.Map<TModel, TDomain>(dataItem);
    }

    public List<TDomain> MapToDomain(IEnumerable<TModel> dataItems)
    {
        return dataItems.Select(this.MapToDomain).ToList();
    }

    public TModel MapToData(TDomain domainItem)
    {
        return Mapper.Map<TDomain, TModel>(domainItem);
    }

    public void MapToOriginalData(TDomain domainItem, TModel dataItem)
    {
        Mapper.Map(domainItem, dataItem);
    }

    public List<TModel> MapToData(IEnumerable<TDomain> domainItems)
    {
        return domainItems.Select(this.MapToData).ToList();
    }
}
Run Code Online (Sandbox Code Playgroud)

AutoMapper 具有高度可配置性,应该能够处理大多数情况。设置一个映射器配置文件,您可以在其中准确地告诉它在映射过程中要做什么:

public class ViewItemProfile : AutoMapper.Profile
{
    protected override void Configure()
    {
        Mapper.CreateMap<Domain, View>()
            .ForMember(x => x.ErrorRequestId, y => y.MapFrom(z => z.ErrorTypeId))
            .ForMember(x => x.Irrelevant, y => y.Ignore());
    }
}
Run Code Online (Sandbox Code Playgroud)