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

本文关键字:详细信息 列表 模型 | 更新日期: 2023-09-27 18:27:23

我需要一些关于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.
} 

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

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

class ObjectiveListVM{
   public int ObjectiveId { get; private set; }
            public string ObjectiveDescription { get; private set; }
            public DateTime StartDate { get; private set; }
}

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

我有一个存储库,它可以给我一个列表或一个目标

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

这就是我实现DDD和Repository模式的方式。我的问题是,我的GetList查询真的很昂贵,它只需要来自3列的数据,但由于我的存储库应该总是返回域对象,我最终返回了一个列表——整个Objective域对象,它有子列表和很多字段。

我想到的解决方案是使用另一个ObjectiveSummary域模型,该模型只有几个字段,由GetList repo方法返回。但它打破了DDD的其他一些原则,主要是ObjectiveSummary是一个贫血领域模型。事实上,它并不是一个真正的模型,它在我的脑海中更像是一个DTO。

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

一些专家能否指出我在实施过程中犯的错误,或者强调一种不用昂贵查询就能解决这个问题的方法?

注意:我能想出几个办法来解决这个问题。但我更感兴趣的是找到一种不违反我所使用的体系结构/模式原则的正确方法。

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

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

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

您想要的是一个查询层。这与CQRS直接相关。查询端返回数据。它没有任何行为,你可以返回最基本的结构。在我所处的C#世界中,我使用DataRowIEnumerable<DataRow>。如果它真的很复杂,我可以选择DTO:

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

试试看。我想你会发现它极大地简化了事情。您的域应该只关心命令/写入方面的问题。

处理它的一种方法是从存储库返回IQueryable<Objective>,而不是IEnumerable<Objective>

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

它将允许您保持存储库的简单性,并在不损失性能的情况下为应用程序/域层的查询添加更多逻辑。以下查询将在数据库服务器上执行,包括对ObjectiveListVM:的投影

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

您可以使用Automapper的Queryable扩展来简化对虚拟机的投影。

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