领域驱动设计:如何为聚合添加新的数据库条目?

问题描述 投票:0回答:1

在领域驱动设计中,当在聚合内创建新对象时,创建数据库条目的最佳方法是什么?

举个例子,考虑一个代表大学学生的

Student
实体。学生参加课程,这些课程是学生聚合的一部分,作为
CourseParticipation
值对象列表。这些对象跟踪学生的参与率和最终成绩。当学生注册新课程时,我们会致电
Student.participateIn(Course)
。在Java中,它看起来像这样:

public class Student {

  private List<CourseParticipation> courseParticipations;

  public void participateIn(Course course) {
    // Business logic: Check if the student is allowed to participate
    
    courseParticipations.add(new CourseParticipation(this, course));
  }
}

现在新的课程参与必须存储在数据库中名为

course_participations
的表中。在我的应用程序中执行此操作的常用方法是调用
CourseParticipationRepository.save(CourseParticipation)
。当在聚合内创建对象时,如何进行此调用?

我能想到或在互联网上读到的选项:

CourseParticipationRepository
注入
Student
并保存在
participateIn(Course)
方法中。

好:

  • 聚合的干净接口:调用者只需执行
    student.participateIn(course)
    即可完成
  • 强制创建新课程参与始终需要新的数据库条目
  • 的规则

坏:

  • 域聚合处理数据库问题
  • 将存储库注入聚合感觉很奇怪。可能有数千个
    Student
    对象...为每个对象提供对存储库单例的引用是一个好主意吗?

返回未保存的

CourseParticipation
对象并让调用者保存它

好:

  • 数据库关注点从领域层移至应用层

坏:

  • 聚合通过返回
    CourseParticipation
    对象
  • 来暴露其内部结构
  • 每个调用者必须记住保存对象
  • 应用逻辑被撕裂;参与新课程总是需要新的数据库条目并不明显

StudentRepository.save(Student)
为每个
CourseParticipationRepository.save
对象
 调用 
CourseParticipation

好:

  • 数据库关注的是存储库内部,而不是聚合
  • 内部
    CourseParticipation
    对象不会暴露给
    participateIn
  • 的调用者

坏:

  • StudentRepository
    需要访问
    CourseParticipation
    对象的内部列表,否则这些对象不会被暴露
  • 如果聚合映射到许多数据库表,则保存方法可能会变得非常复杂
  • 避免不必要的数据库调用(即保存未更改的条目)可能很困难

重新设计数据库表或使用对象数据库

我在很多有关领域驱动设计的文章中读到了这个建议。这对于绿地项目来说很有意义。但这不是我正在开发的应用程序的一个选项。

最好或最常见的选择是什么?还有其他解决办法吗?

domain-driven-design aggregateroot
1个回答
0
投票

聚合不应该关心表结构。这(以及聚合是一致性单位的要求)最终意味着第三种方法就是方法。

StudentRepository 需要访问 CourseParticipation 对象的内部列表,否则该对象不会被公开

课程参与列表是

Student
的一部分。拯救学生意味着拯救参与。

如果聚合映射到许多数据库表,则保存方法可能会变得非常复杂 避免不必要的数据库调用(即保存未更改的条目)可能很困难

不幸的是,这就是休息时间。

DDD 聚合基本上采用对象存储(或事件存储,如果是事件源),因为该抽象与保存/检索聚合所需的最低功能相匹配。关系模式,尤其是追求更高范式的关系模式,将会带来开销/复杂性。

© www.soinside.com 2019 - 2024. All rights reserved.