在模型层中,与直接引用相反,使用id组合类型是好主意吗?
本文关键字:组合 id 使用 类型 好主意 模型 引用 | 更新日期: 2023-09-27 18:04:22
虽然这个问题是在MVVM的背景下,但我认为它可以推广到任何MV*架构。
在创建模型层时,我习惯直接引用对象来表示关系,如下所示:
class Course {
CourseID ID { get; }
string Name { get; }
}
class Student {
IEnumerable<Course> EnrolledCourses { get; }
}
然而,我发现从存储中重建这样的对象层次结构变得越来越麻烦。如果在模型层没有DI的好处,我将面临这样一个不愉快的选择:是使用带有所有相关属性的重型ORM和其他令人头疼的选择,还是使用微型ORM(我的偏好),然后辛苦地手工重建对象图。
我正在考虑完全放弃直接引用的想法,而采用如下方式:
class Course {
CourseID ID { get; }
string Name { get; }
}
class Student {
IEnumerable<CourseID> EnrolledCourses { get; }
}
这样,我的模型层开始更接近于关系数据,我一直认为这在传统上是不受欢迎的(因此更倾向于orm)。
在我的代码中,应用程序的数据通常通过Repository模式暴露给更高的级别,作为响应式提要和/或iEnumerables。这使得根据需要通过查询和/或按键筛选来检索和显示相关数据变得非常容易。不像直接引用那么简单,但也很接近。
那么——反对在不引用其他类型的情况下建模域对象的主要论点是什么?另外,我试着找到关于这个的讨论,但没有看到太多,可能是我错过了正确的搜索条件?
在任何希望可维护的应用程序中,都需要尊重关注点分离。MV*总是UI层的一部分,大多数时候你也有一个业务(域)层和一个持久化层(DAL)。
SoC意味着您可以一次专注于一层。ViewModel是为视图设计的,域模型只关心业务,而持久化模型知道保存和查询。它们是相关的,但并不相同,最好将它们视为不同的。
当您对领域建模时,您不关心其他层,您希望最好地表示业务概念(这是非常棘手的,因为它们中的许多看起来很容易建模,但这是一个陷阱!)和这些概念的用例。这里没有任何参考,只有使用业务概念的业务流程,也就是说,即使你在写代码,你也应该在更高的层次上思考,而不是在技术层面上思考。
例如,您向我们展示的代码看起来确实像一个视图模型,因为Student的Domain概念可能不涉及课程(您的视图需要它们一起)。您有学生、课程,这两个概念在许多业务场景中一起工作。它可能是更好的(我不知道你的域名的确切细节)有一个服务,其目的是在课程中招收学生。从持久性的角度来看,您可能有一些东西作为注册学生的存储库,即CourseId和StudentId的集合。如果上面提到的服务不包含业务逻辑,它可能可以直接在持久性中实现。几乎所有的设计决策都需要对领域有正确的理解,所以我在这里只是猜测,但我试图展示如何思考。
请注意,在不同的上下文中,你真的不需要完整的对象,只需要它的"短"形式,通常意味着引用(如Id)。但是从上下文的角度来看,这个参考代表了一个概念。请注意,实体或引用不是用于导航目的的。它们的存在是因为它们有助于定义领域概念。
同样,将业务对象定义为作为其他对象的容器的单一目的是没有意义的。在领域建模中,与的关系应该被视为是由定义的。
您应该熟悉CQRS(分离写和读)。这将使保存/恢复业务模型变得微不足道,同时允许您使用查询。而且你不需要一个ORM。
底线是,您应该根据您正在工作的层(关注点)对事物进行建模。然后使用映射器将相关模型从一个层/上下文"翻译"到另一个层/上下文。