我几个月前改进了我们的可用性引擎,以便将我们的逻辑从数据库转移到微服务。那时,业务逻辑非常简单:
资源(会议室,办公桌,空办公室,设备)仅在给定时间范围内可用(如果尚未预订)(即:不使用相同资源进行其他预订)
当资源不可用时,必须计算最接近的可用时间范围
为了满足这些要求,我在下面构建了一小段代码:
public class Schedule : IAggregateRoot
{
public int CityId { get; }
public int BuildingId { get; }
public int CentreId { get; }
public int ResourceId { get; }
public ICollection<Booking> Bookings { get; }
public Schedule(int cityId, int buildingId, int centreId, int resourceId, IEnumerable<Booking> bookings)
{
CityId = cityId;
BuildingId = buildingId;
CentreId = centreId;
ResourceId = resourceId;
Bookings = new List<Booking>(bookings);
}
public bool IsTimeSlotFree(DateTimeOffset startDate, DateTimeOffset endDate)
=> Bookings.Any(/* Predicate */);
public IEnumerable<Availability> GetFreeTimeSlots(
DateTimeOffset startDate,
DateTimeOffset endDate,
TimeSpan duration)
{
var nbSlots = Math.Floor((endDate - startDate) / duration);
for(int i=0; i<nbSlots; i++) {
/* yield return availability */
}
}
}
public class Availability : ValueObject
{
public DateTimeOffset StartDate { get; set; }
public DateTimeOffset EndDate { get; set; }
public int ResourceId { get; set; }
public bool IsAvailable { get; set; }
}
public class Resource : Entity
{
public string Code { get; set; }
// Required for EF Core
protected Resource() { }
}
public class Booking : Entity
{
public DateTimeOffset StartDate { get; set; }
public DateTimeOffset EndDate { get; set; }
public string Status { get; set; }
public int ResourceId { get; set; }
// Required for EF Core
protected Booking() { }
}
几周前,我被要求处理组合房间(两个较小的房间可以合并成一个更大的组合房间)。在这种情况下,组合的房间只有它的子房间可用。换句话说,我需要检查几个计划以确定可用性,不幸的是我当前的抽象级别不允许(一个计划,一个房间)。
我找到的唯一方法是检索资源及其子项(=子房间),然后创建一个包含ResourceId和预订字典的计划。
public class Resource : Entity
{
public string Code { get; set; }
public Resource Parent { get; set; }
public ICollection<Resource> Children { get; set; }
// Required for EF Core
protected Resource() { }
}
public class Schedule : IAggregateRoot
{
public int CityId { get; }
public int BuildingId { get; }
public int CentreId { get; }
public int ResourceId { get; }
public IDictionnary<int, ICollection<Bookings>> Bookings
(...)
}
我发现这个解决方案并不优雅。对我来说,更好的解决方案是检索计划并将它们组合以确定实际可用性。我尝试了几种解决方案,但我最终写了意大利面条代码。
您对如何重新设计我的聚合以正确处理这个新概念有什么想法吗?
谢谢你, SEB
答案 0 :(得分:1)
猜测,核心问题是您在模型中缺少域概念。
我的猜测是您缺少描述可用库存的产品目录的表示。在该目录中,您将拥有#101房间的入口和#102房间的入口。如果这些房间可以打包在一起,那么您还可以获得包裹[#101和#102]的条目。
因此,包的可用性很容易 - 采用包中元素的时间表的交集。由于您知道包的内容,因此很容易找到协调所需的计划。
请注意,您可以更新目录 - 添加或删除包 - 而不会以任何方式影响预订。
当然,你必须弄明白你将如何处理多个房间的实际预订。有几种可能性;最简单的,也就是我猜测的用户最熟悉的是,允许时间表聚合接受重叠预订,设置双重预订标记以跟踪需要采取补偿措施的情况。
另一种选择是使用传奇模式预订包裹;如果无法预订整个套餐,那么进行预订编排的流程会知道取消预订房间。
您可以通过将所有计划移动到单个聚合中来简化操作;将一致性边界提升到更大的范围(可能是财产,而不是单个房间);这会影响较大房间的自治和规模。
答案 1 :(得分:0)
几乎所有包含资源调度的域模型都将Day作为单独的聚合概念。没有它,你将永远聚合。不同的背景可以保持一天的不同表现形式: