领域模型和列表/详细信息页面
Domain models and the List / Detail page
我需要一些关于 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 个视图,一个是列表视图,另一个是详细信息视图。
列表视图有一个只有 3 个字段的 IEnumerable
class ObjectiveListVM{
public int ObjectiveId { get; private set; }
public string ObjectiveDescription { get; private set; }
public DateTime StartDate { get; private set; }
}
详细信息视图有一个 ObjectiveDetailViewModel,它包含 Objective 域模型中 90% 的字段以及更多字段。
我有一个存储库,可以获取一个列表或一个 objective
IObjectiveRepo
{
Objective GetById();
IEnumerable<Objective> GetList();
}
这就是我实现 DDD 和存储库模式的方式。
我的问题是,我的 GetList 查询非常昂贵,它只需要来自 3 列的数据,但由于我的存储库应该始终 return 域对象,我最终 return 列出了整个 Objective 具有子列表和大量字段的域对象。
我想到的解决方案是使用另一个 Objective 摘要域模型,它只有几个字段并且由 GetList 存储库方法 return 编辑。但它随后打破了 DDD 的其他一些原则,主要是 ObjectiveSummary is a Anemic Domain model 。事实上它不是一个真正的模型,在我的脑海中它更像是一个 DTO。
这是一个很常见的场景,我觉得我在 DDD/存储库模式的实现或解释中遗漏了一些非常基本的东西。
一些专家能否指出我在实施中所犯的错误,或者强调一种无需昂贵查询即可解决此问题的方法?
注意:我可以想出一些方法来解决这个问题 problem.But 我更感兴趣的是找到不违反我正在使用的 architecture/pattern 原则的正确方法。
一种处理方法是从您的存储库中 return IQueryable<Objective>
而不是 IEnumerable<Objective>
.
public interface IObjectiveRepository
{
Objective GetById();
IQueryable<Objective> GetList();
}
它将允许您保持存储库简单并向 application/domain 层中的查询添加更多逻辑,而不会损失性能。以下查询将在数据库服务器上执行,包括投影到 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 来更轻松地投影到 VM。
return _repository
.GetList()
.ProjectTo<ObjectiveListVM>()
.ToList();
您不应查询您的域模型。聚合始终是完整加载的,因此它不适合查询。
一旦您想到延迟加载,您可能没有使用最佳方法。延迟加载是邪恶的。不要这样做:)
您所追求的是某种查询层。这与 CQRS 直接相关。查询端只有returns条数据。它没有任何行为,您 return 可以使用最基本的结构。在我所在的 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);
}
试一试。我想你会发现它极大地简化了事情。您的域应该只关注 command/write 方面的事情。
我需要一些关于 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 个视图,一个是列表视图,另一个是详细信息视图。
列表视图有一个只有 3 个字段的 IEnumerable
class ObjectiveListVM{
public int ObjectiveId { get; private set; }
public string ObjectiveDescription { get; private set; }
public DateTime StartDate { get; private set; }
}
详细信息视图有一个 ObjectiveDetailViewModel,它包含 Objective 域模型中 90% 的字段以及更多字段。
我有一个存储库,可以获取一个列表或一个 objective
IObjectiveRepo
{
Objective GetById();
IEnumerable<Objective> GetList();
}
这就是我实现 DDD 和存储库模式的方式。 我的问题是,我的 GetList 查询非常昂贵,它只需要来自 3 列的数据,但由于我的存储库应该始终 return 域对象,我最终 return 列出了整个 Objective 具有子列表和大量字段的域对象。
我想到的解决方案是使用另一个 Objective 摘要域模型,它只有几个字段并且由 GetList 存储库方法 return 编辑。但它随后打破了 DDD 的其他一些原则,主要是 ObjectiveSummary is a Anemic Domain model 。事实上它不是一个真正的模型,在我的脑海中它更像是一个 DTO。
这是一个很常见的场景,我觉得我在 DDD/存储库模式的实现或解释中遗漏了一些非常基本的东西。
一些专家能否指出我在实施中所犯的错误,或者强调一种无需昂贵查询即可解决此问题的方法?
注意:我可以想出一些方法来解决这个问题 problem.But 我更感兴趣的是找到不违反我正在使用的 architecture/pattern 原则的正确方法。
一种处理方法是从您的存储库中 return IQueryable<Objective>
而不是 IEnumerable<Objective>
.
public interface IObjectiveRepository
{
Objective GetById();
IQueryable<Objective> GetList();
}
它将允许您保持存储库简单并向 application/domain 层中的查询添加更多逻辑,而不会损失性能。以下查询将在数据库服务器上执行,包括投影到 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 来更轻松地投影到 VM。
return _repository
.GetList()
.ProjectTo<ObjectiveListVM>()
.ToList();
您不应查询您的域模型。聚合始终是完整加载的,因此它不适合查询。
一旦您想到延迟加载,您可能没有使用最佳方法。延迟加载是邪恶的。不要这样做:)
您所追求的是某种查询层。这与 CQRS 直接相关。查询端只有returns条数据。它没有任何行为,您 return 可以使用最基本的结构。在我所在的 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);
}
试一试。我想你会发现它极大地简化了事情。您的域应该只关注 command/write 方面的事情。