【发布时间】:2020-04-28 00:03:01
【问题描述】:
我正在以 DDD 方式使用 C# .NET 开发应用程序。我也查了eshopcontainers,但它并没有解释我想知道什么,所以让我在这里提出一个问题。我的问题是
- 是否可以直接从批处理操作部分更新根聚合?
详情
我正在开发一个 RSVP 应用程序。现在我想做的是向尚未投票的人发送提醒邮件。我的领域模型和基础设施层是这样的。
//Domain Model
class RSVP //RootAggreagate
{
public long Id {get; private set;}
public List<TimeSlot> TimeSlots {get; private set;}
public AutoRemindRule AutoRemindRule {get; private set;}
}
class AutoRemindRule
{
public long Id {get; private set;}
public int IntervalHour { get; private set; }
public DateTimeOffset NextTriggerDate { get; private set; }
public DateTimeOffset RemindBeginDate { get; private set; }
//Foreign Key for Plan
public long RSVPId
void SetNextTriggerDate()
{
//Compute NewNextTriggerDate based on IntervalHour and RemindBeginDate field.
NextTriggerDate = NewNextTriggerDate;
}
}
//Infrastructure Layer (EF Core)
public class MyDbContext : DbContext
{
//Plan Aggregate
public DbSet<RSVP> RSVPs { get; set; }
public DbSet<TimeSlot> TimeSlots { get; set; }
public DbSet<AutoRemindRule> AutoRemindRules { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
...
}
}
在这个模型中,我想运行一个批处理来定期检查AutoRemindRules 中的NextTriggerDate,如果NextTriggerDate 比现在更旧,该批处理将邮件发送给没有投票RSVP 的用户。最终,批处理通过调用SetNextTriggerDate 更新NextTriggerDate。如果我在批处理的 Usecase(Application) 层编写如下代码,我可以实现我想要的。但是,我不认为这些代码遵循 DDD 规则,因为它会部分更新聚合根。在应用层写这样的代码可以吗,或者如果没有,谁能告诉我更好的编码方式?
//Usecase(Application) layer in a batch
using (var context = new MyDbContext)
{
var rules = context.AutoRemindRules.Where(i => i.NextTiggerdate < DateTimeOffset.Now);
foreach (var rule in rule)
{
SendRemindMail();
rule.SetNextTriggerDate();
context.SaveChanges();
}
}
更新
另一种方法是创建一个方法来更新聚合根中的AutoRemindRule,并且批处理使用该方法。但是,我关心的是性能和数据库的负载。在这种情况下,除了AutoRemindRule 记录之外,该批次还必须读取一堆不必要的 RSVP 记录。我想知道是否有另一种方法可以在保持 DDD 方式的同时减少 DB 的负载。
【问题讨论】:
-
如果您直接访问实体,聚合根的意义何在?更新应该通过聚合根,而不是实体。
-
是的,我们应该这样做。但是,我担心的是数据库的性能和负载。批处理想要监视和更新
NextTriggerDate的值,并且批处理作业不需要RSVP 实体。如果我们通过根聚合中的方法更新NextTriggerDate,批处理必须读取一堆不必要的RSVP。记录。
标签: c# .net domain-driven-design ef-core-2.0