对于我一直在与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 /存储库模式时遗漏了一些非常基本的东西。
有些专家可以指出我在实施过程中犯的错误,或突出显示解决此问题的方法而无需昂贵的查询吗?
注意:我可以想办法解决这个问题。但是我更感兴趣的是找到正确的方法,不会破坏我正在使用的架构/模式的原则。
答案 0 :(得分:4)
您不应该查询您的域模型。聚合总是完全加载,因此它不适合查询。
一旦考虑到延迟加载,您可能就没有使用最佳方法。懒惰是邪恶的。不要这样做:)
您所追求的是各种各样的查询图层。这与CQRS直接相关。查询端仅返回数据。它没有任何行为,您可以返回最基本的结构。在C#世界中,我也使用DataRow
或IEnumberable<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();