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

问题描述 投票:0回答:2

我需要一些关于 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 个视图,一个是列表视图,另一个是详细信息视图。

ListView 有一个 IEnumerable,它只有 3 个字段

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

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

我有一个存储库,可以为我提供一个列表或一个目标

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

这就是我实现 DDD 和存储库模式的方式。 我的问题是,我的 GetList 查询非常昂贵,它只需要 3 列的数据,但由于我的存储库应该始终返回域对象,所以我最终返回整个 Objective 域对象的列表,其中包含子列表和许多字段。

我想到的解决方案是拥有另一个 ObjectiveSummary 域模型,它只有几个字段,并由 GetList 存储库方法返回。但它随后打破了 DDD 的一些其他原则,主要是 ObjectiveSummary 是一个贫血领域模型。这不是一个模型,它更像是我脑海中的 DTO。

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

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

注意:我可以想出几种解决这个问题的方法。然而,我更感兴趣的是找到不违反我正在使用的架构/模式原则的正确方法。

c# asp.net-mvc model-view-controller domain-driven-design repository-pattern
2个回答
4
投票

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

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

您所追求的是某种“查询层”。这与CQRS直接相关。查询端返回数据。它没有任何行为,您可以返回最基本的结构。在我所在的 C# 世界中,我使用 DataRow

IEnumerable<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 方面。


0
投票
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 的 
可查询扩展

来更轻松地投影到虚拟机。 return _repository .GetList() .ProjectTo<ObjectiveListVM>() .ToList();

© www.soinside.com 2019 - 2024. All rights reserved.