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

时间:2015-12-18 16:59:12

标签: c# asp.net-mvc model-view-controller domain-driven-design repository-pattern

对于我一直在与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个视图,一个是列表视图,另一个是详细信息视图。

列表视图有一个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和Repository模式的方法。 我的问题是,我的GetList查询非常昂贵,它只需要3列数据,但由于我的存储库应该总是返回域对象,我最终返回一个列表,其中包含子列表和大量字段的整个Objective域对象。 / p>

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

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

有些专家可以指出我在实施过程中犯的错误,或突出显示解决此问题的方法而无需昂贵的查询吗?

注意:我可以想办法解决这个问题。但是我更感兴趣的是找到正确的方法,不会破坏我正在使用的架构/模式的原则。

2 个答案:

答案 0 :(得分:4)

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

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

您所追求的是各种各样的查询图层。这与CQRS直接相关。查询端返回数据。它没有任何行为,您可以返回最基本的结构。在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);
}

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

答案 1 :(得分:0)

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

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

它将允许您保持存储库简单,并为应用程序/域层中的查询添加更多逻辑,而不会降低性能。将在db服务器上执行以下查询,包括对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来更轻松地投影到虚拟机。

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