C# CQRS中写端DDD中的时间序列/时间数据
我很难理解如何在DDD中支持时间序列/时态数据,以及如何使用CQR在写端处理它。最后,我想找到一个解决方案,也发挥良好的事件来源 以温度预测为例,温度变化也可能影响区域/位置的预测能源需求。假设温度预测可以追溯到遥远的未来(基于历史数据),如果不对加载的数据量施加限制,将所有预测加载到C# CQRS中写端DDD中的时间序列/时间数据,c#,domain-driven-design,time-series,cqrs,event-sourcing,C#,Domain Driven Design,Time Series,Cqrs,Event Sourcing,我很难理解如何在DDD中支持时间序列/时态数据,以及如何使用CQR在写端处理它。最后,我想找到一个解决方案,也发挥良好的事件来源 以温度预测为例,温度变化也可能影响区域/位置的预测能源需求。假设温度预测可以追溯到遥远的未来(基于历史数据),如果不对加载的数据量施加限制,将所有预测加载到位置集合中是不切实际的 记住事件来源时,同步/存储此类数据以在CQR的写端使用的好方法/推荐方法是什么? 我的以下尝试(选项A或B)是否被视为合适的DDD/CQRS解决方案? 备选方案A: 允许独立更新温度,并使用
位置
集合中是不切实际的
记住事件来源时,同步/存储此类数据以在CQR的写端使用的好方法/推荐方法是什么?
我的以下尝试(选项A或B)是否被视为合适的DDD/CQRS解决方案?
备选方案A:
允许独立更新温度,并使用process manager/saga订阅事件,然后重新计算需求。此解决方案将有助于保持聚合大小较小,但感觉聚合边界可能是错误的,因为需求取决于温度,现在分布在命令/事件中
// OverrideTemperatureForecastCommandHandler.cs
public void Handle(OverrideTemperatureForecast cmd)
{
var from = cmd.TemperatureOverrides.Min(t => t.DateTime);
var to = cmd.TemperatureOverrides.Max(t => t.DateTime);
TemperatureForecasts forecasts = temperatureForecastRepository.GetByLocation(cmd.LocationId, from, to);
forecasts.Override(cmd.TemperatureOverrides);
temperatureForecastRepository.Save(forecasts);
// raises
// TemperatureForecastsOverridden(locationId, overrides)
}
// TemperatureForecastsOverriddenProcessManager.cs
public void Handle(TemperatureForecastsOverridden @event)
{
var from = cmd.TemperatureOverrides.Min(t => t.DateTime);
var to = cmd.TemperatureOverrides.Max(t => t.DateTime);
// issue a command to recalculate the energy demand now temperature has changed...
commandBus.Send(new RecalculateEnergyDemand
{
LocationId = @event.LocationId,
From = from,
To = to
}));
}
// RecalculateEnergyDemandCommandHandler.cs
public void Handle(RecalculateEnergyDemand cmd)
{
EnergyDemand demandForecasts = energyDemandForecastRepository.GetByLocation(cmd.LocationId, cmd.From, cmd.To);
// have to fetch temperature forecasts again...
TemperatureForecasts temperatureForecasts = temperatureForecastRepository.GetByLocation(cmd.LocationId, cmd.From, cmd.To);
demandForecasts.AdjustForTemperature(temperatureForecasts);
energyDemandForecastRepository.Save(demandForecasts);
// raises
// ForecastDemandChanged(locationId, demandforecasts)
}
备选案文B:
根据给定的日期范围在内部创建单个聚合“位置”和预加载预测数据。从DDD行为的角度来看,这感觉更干净,但是加载受限于时间范围的聚合对我来说有点尴尬(或者仅仅是我自己?)。如果不限制预测值的大小,“位置”总量可能会变得巨大
// OverrideTemperatureForecastCommandHandler.cs
public void Handle(OverrideTemperatureForecast cmd)
{
var from = cmd.TemperatureOverrides.Min(t => t.DateTime);
var to = cmd.TemperatureOverrides.Max(t => t.DateTime);
// use from/to to limit internally the range of temperature and demand forecasts that get loaded in to the aggregate.
Location location = locationRepository.Get(cmd.LocationId, from, to);
location.OverrideTemperatureForecasts(cmd.TemperatureOverrides);
locationRepository.Save(forecasts);
// raises
// TemperatureForecastsOverridden(locationId, overrides)
// ForecastDemandChanged(locationId, demandforecasts)
}
对于选项A或B,读取端的反规范化器可能类似于:
// TemperatureDenormaliser.cs
public void Handle(TemperatureForecastsOverridden @event)
{
var from = @event.Overrides.Min(t => t.DateTime);
var to = @event.Overrides.Max(t => t.DateTime);
var temperatureDTOs = storage.GetByLocation(@event.LocationId, from, to);
// TODO ... (Add or update)
storage.Save(temperatureDTOs);
}
// EnergyDemandDenormalizer.cs
public void Handle(ForecastDemandChanged @event)
{
var from = @event.Overrides.Min(t => t.DateTime);
var to = @event.Overrides.Max(t => t.DateTime);
var demandDTOs = storage.GetByLocation(@event.LocationId, from, to);
// TODO ... (Add or update)
storage.Save(demandDTOs);
}
对于您的两个示例,事件来源都不是一个选项 随着新事件的出现,旧事件变得无关紧要。这些不一定需要在一个集合中;在整个阅读历史中,没有不变量可以保护
相反,一系列事件可以在一个传奇中管理,只保留有限的知识,并级联成结果事件。假设您已经在事件源中寻找聚合。您计划如何实现TemperatureForecstrepository.GetByLocation或locationRepository.Get(LocationId、from、to)?事件存储中的所有内容都是用于聚合的一组事件。您的存储库真正能做的就是按顺序读取并应用它们。你得到了完整的聚合,就是这样,你不能仅仅过滤掉“一些东西”。你可能需要考虑将温度预测排除在域名之外。谢谢AlxyZimimalv,是的,这是有道理的,我的例子不能与事件采购相结合。我认为你提出的把温度从这个领域中去掉的建议使我走上了正确的轨道。这基本上总结了我一直在努力解决的问题,Udi和Greg Young提供了一些很好的反馈。这也很好地将责任划分到不同的有界上下文中。我可能需要考虑级联事件(传奇)而不是命令。那么你最终做了什么?也许你可以回答你自己的问题并展示一个有效的解决方案?