域模型和列表/详细信息页面
本文关键字:详细信息 列表 模型 | 更新日期: 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#世界中,我使用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);
}
试试看。我想你会发现它极大地简化了事情。您的域应该只关心命令/写入方面的问题。
处理它的一种方法是从存储库返回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();