聚合内的聚合列表

时间:2019-10-08 13:35:08

标签: sql-server design-patterns domain-driven-design microservices ef-core-2.0

我正在使用DDD聚合对学生和出勤功能进行建模。我最终得到的是学生班级,其中包含一份出勤记录列表。我正在使用EF Core加载学生以及与该学生相关的所有出勤。

因此,每天都有针对学生的出勤记录。一天中的出勤记录可以多次更新。我最终在Student类上创建了一个公共方法,称为CreateOrUpdateAttendance(Date date,AttendanceDetails勤工),如果没有创建新的勤工实例,它将内部检查给定日期是否有任何勤工记录,请使用提供的勤工更新该勤工记录详细信息添加/更新与学生相关的出勤列表。因此,每次为学生更新/创建一个出勤记录时,都会从数据库中查询学生实体以及所有出勤记录。根据从输入中收到的ID来查询学生,以检查提供的ID是否有效。

问题在于,随着时间的流逝,与学生相关的出勤记录会很多,这意味着不必要地拉扯与学生相关的所有出勤记录,这将导致查询性能下降。

学生在这里是正确的根吗?不幸的是,EF核心尚不支持过滤子对象。

我的问题是如何处理需要在聚合内更新子实体的用例?更具体地说,聚合内的实体列表中的单个实体?

在这种情况下,我应该将出勤视为不同的汇总吗?这样我就可以独立于学生记录查询出勤记录了吗?

我最后打了两次电话给数据库,一个是检查学生(不加载出勤情况),另一个是获取出勤记录。

我在这里想念什么吗?我应该重新考虑设计吗?任何指导都会很有帮助。

1 个答案:

答案 0 :(得分:0)

  

学生在这里是正确的根吗?

集合是一致性边界。存在确保包含在其中的实体与您的业务规则相关的状态处于一致(即有效)的状态。您尚未描述应确保的任何业务规则或验证,因此我不知道Student是正确的汇总。继续阅读...

  

不幸的是,EF核心还不支持过滤子对象。

EF Core不支持过滤子集合,但是可能还有其他方法可以实现此目的。这是一些伪代码:

var query = 
    from s in ctx.Students
    where s.Id == 1 // Student filter here
    select new 
    {
        Student = s,
        Student = 
            from sa in s.StudentAttendances
            where sa. // Apply filter here
            select sa
    };

// Perform the query against the DB and then return the Student object
// EF will wire up the relationships for you and because you went to the
// DB first before pulling the student, the data is local and you will
// have the full tree
var student = query.ToList().Select(x => x.Student).FirstOrDefault();
  

在这种情况下,我应该将出勤视为不同的汇总吗?这样我就可以独立于学生记录查询出勤记录了吗?

这取决于您的业务规则。学生和出勤的寿命是多少?学生可以参加任何数量的出勤吗?多考虑您的写用例,而不是您的读用例。您是否需要加载StudentAttendances?这仅仅是一个阅读用例吗?

还要考虑一个学生综合人数是否足够。当您只想更改电话号码时,是否应该加载所有的出勤记录?就像我们有绑定的上下文一样,您可能会考虑使用绑定的聚合,例如绑定上下文中聚合的垂直分区将听起来像一个单一的大型概念拆分为几个较小的概念。

您可以拥有:

  • 具有汇总的出勤列表的学生集合(如上所述)
  • 学生出勤汇总(如您所述)
  • StudentWithAttendance汇总与学生汇总分开,并用于不同的用例
  

我在这里想念什么吗?我应该重新考虑设计吗?

这取决于。通常,我建议在域级别而不是数据库级别考虑更多。多考虑写而不是读。

EF甚至在我们为Domain建模时,EF仍以某种方式迫使我们以关系的方式进行思考,但是我们应该克服这种冲动,并在可能的情况下将EF放到简单的持久性机制中,而不要让它驱动我们的Domain设计决策。