领域模型和列表/详细信息页面

Domain models and the List / Detail page

我需要一些关于 DDD 问题的建议。

我有一个域模型,它是聚合根

public class  Objective {
   public int ObjectiveId { get; private set; }

        public string ObjectiveDescription { get; private set; }

        public DateTime StartDate { get; private set; }

        public DateTime TargetDate { get; private set; }

        public DateTime? CompletedDate { get; private set; }

        public int EmploymentId { get; private set; }

        public List<Skill> RelatedSkills { get; private set; }

        public List<Goal> RelatedGoals { get; private set; }
       // few more properties.
} 

我有 2 个视图,一个是列表视图,另一个是详细信息视图。

列表视图有一个只有 3 个字段的 IEnumerable

class ObjectiveListVM{
   public int ObjectiveId { get; private set; }

            public string ObjectiveDescription { get; private set; }

            public DateTime StartDate { get; private set; }
}

详细信息视图有一个 ObjectiveDetailViewModel,它包含 Objective 域模型中 90% 的字段以及更多字段。

我有一个存储库,可以获取一个列表或一个 objective

IObjectiveRepo
{
   Objective GetById();
   IEnumerable<Objective> GetList();
}

这就是我实现 DDD 和存储库模式的方式。 我的问题是,我的 GetList 查询非常昂贵,它只需要来自 3 列的数据,但由于我的存储库应该始终 return 域对象,我最终 return 列出了整个 Objective 具有子列表和大量字段的域对象。

我想到的解决方案是使用另一个 Objective 摘要域模型,它只有几个字段并且由 GetList 存储库方法 return 编辑。但它随后打破了 DDD 的其他一些原则,主要是 ObjectiveSummary is a Anemic Domain model 。事实上它不是一个真正的模型,在我的脑海中它更像是一个 DTO。

这是一个很常见的场景,我觉得我在 DDD/存储库模式的实现或解释中遗漏了一些非常基本的东西。

一些专家能否指出我在实施中所犯的错误,或者强调一种无需昂贵查询即可解决此问题的方法?

注意:我可以想出一些方法来解决这个问题 problem.But 我更感兴趣的是找到不违反我正在使用的 architecture/pattern 原则的正确方法。

一种处理方法是从您的存储库中 return IQueryable<Objective> 而不是 IEnumerable<Objective>.

public interface IObjectiveRepository
{
   Objective GetById();
    IQueryable<Objective> GetList();
}

它将允许您保持存储库简单并向 application/domain 层中的查询添加更多逻辑,而不会损失性能。以下查询将在数据库服务器上执行,包括投影到 ObjectiveListVM:

public IReadOnlyList<ObjectiveListVM> GetSummaryList()
{
    return _repository
        .GetList()
        .Select(o => new ObjectiveListVM
        {
            ObjectiveId = o.ObjectiveId,
            ObjectiveDescription = o.ObjectiveDescription,
            StartDate = o.StartDate
        })
        .ToList();
}

您可以使用 Automapper 的 Queryable extensions 来更轻松地投影到 VM。

return _repository
    .GetList()
    .ProjectTo<ObjectiveListVM>()
    .ToList();

您不应查询您的域模型。聚合始终是完整加载的,因此它不适合查询。

一旦您想到延迟加载,您可能没有使用最佳方法。延迟加载是邪恶的。不要这样做:)

您所追求的是某种查询层。这与 CQRS 直接相关。查询端只有returns条数据。它没有任何行为,您 return 可以使用最基本的结构。在我所在的 C# 世界中,我使用 DataRowIEnumberable<DataRow>。如果它真的很复杂,我可能会选择 DTO:

public interface IObjectiveQuery
{
    DataRow ForList(int id);
    bool Contains(string someUniqueKey);
    IEnumerable<DataRow> Search(string descriptionLike, DateTime startDate);
    string Description(int id);
}

试一试。我想你会发现它极大地简化了事情。您的域应该只关注 command/write 方面的事情。