如何确定组合房间可用性 DDD
How to determine combined room availability DDD
我几个月前改进了我们的可用性引擎,以便将我们的逻辑从数据库转移到微服务。当时的业务逻辑还算简单:
资源(会议室、办公桌、空办公室、设备)仅在尚未预订的情况下(即没有其他预订使用同一资源)在给定时间范围内可用
当资源不可用时,必须计算最接近的可用时间范围
为了满足这些要求,我构建了下面的一小段代码:
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() { }
}
几周前我被要求处理组合房间(两个较小的房间可以合并成一个更大的组合房间)。在这种情况下,只有 sub-rooms 和它本身可用的组合房间才可用。换句话说,我需要检查多个时间表以确定可用性,不幸的是我当前的抽象级别不允许这样做(一个时间表,一个房间)。
我找到的唯一方法是检索资源及其 children(=子房间),然后创建一个包含 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
(...)
}
我觉得这个解决方案不是很优雅。对我来说,更好的解决方案是检索时间表并将它们组合起来以确定实际可用性。我尝试了几种解决方案,但我 ended-up 编写了意大利面条代码。
关于我如何 re-design 我的聚合正确处理这个新概念,你有什么想法吗?
谢谢,
塞布
据推测,核心问题是您的模型中缺少领域概念。
我的猜测是您缺少描述可用库存的产品目录表示。在该目录中,您将有一个房间 #101 的条目和一个房间 #102 的条目。如果这些房间可以打包在一起,那么您也将有一个打包条目[#101 和#102]。
所以包的可用性很容易 - 获取包中元素的时间表的交集。由于您知道包裹的内容,因此很容易找到您需要协调的时间表。
请注意,您可以更新目录 - 添加或删除套餐 - 不会以任何方式影响预订。
当然,您必须弄清楚您将如何处理多个房间的实际预订。有几种可能性;最简单的,也是我想您的用户最熟悉的一种,是允许计划聚合接受重叠预订,设置重复预订标志以跟踪需要采取补偿措施的情况。
另一种选择是使用 saga 模式预订套餐;如果无法预订整个套餐,则进行预订编排的流程知道取消房间预订。
您可以通过将所有计划移动到一个集合中来简化事情;将一致性边界提高到更大的范围(可能 属性,而不是单个房间);这牺牲了更大房间的自主权和规模。
几乎所有包含资源调度的域模型都将日作为单独的聚合概念。没有它,你将永远聚集在一起。不同的上下文可以保留不同的日期表示:
- 预订可以有房型和空房情况
- 定价可以有房型和价格
- 接待处可以分配房间、到达和离开
我几个月前改进了我们的可用性引擎,以便将我们的逻辑从数据库转移到微服务。当时的业务逻辑还算简单:
资源(会议室、办公桌、空办公室、设备)仅在尚未预订的情况下(即没有其他预订使用同一资源)在给定时间范围内可用
当资源不可用时,必须计算最接近的可用时间范围
为了满足这些要求,我构建了下面的一小段代码:
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() { }
}
几周前我被要求处理组合房间(两个较小的房间可以合并成一个更大的组合房间)。在这种情况下,只有 sub-rooms 和它本身可用的组合房间才可用。换句话说,我需要检查多个时间表以确定可用性,不幸的是我当前的抽象级别不允许这样做(一个时间表,一个房间)。
我找到的唯一方法是检索资源及其 children(=子房间),然后创建一个包含 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
(...)
}
我觉得这个解决方案不是很优雅。对我来说,更好的解决方案是检索时间表并将它们组合起来以确定实际可用性。我尝试了几种解决方案,但我 ended-up 编写了意大利面条代码。
关于我如何 re-design 我的聚合正确处理这个新概念,你有什么想法吗?
谢谢, 塞布
据推测,核心问题是您的模型中缺少领域概念。
我的猜测是您缺少描述可用库存的产品目录表示。在该目录中,您将有一个房间 #101 的条目和一个房间 #102 的条目。如果这些房间可以打包在一起,那么您也将有一个打包条目[#101 和#102]。
所以包的可用性很容易 - 获取包中元素的时间表的交集。由于您知道包裹的内容,因此很容易找到您需要协调的时间表。
请注意,您可以更新目录 - 添加或删除套餐 - 不会以任何方式影响预订。
当然,您必须弄清楚您将如何处理多个房间的实际预订。有几种可能性;最简单的,也是我想您的用户最熟悉的一种,是允许计划聚合接受重叠预订,设置重复预订标志以跟踪需要采取补偿措施的情况。
另一种选择是使用 saga 模式预订套餐;如果无法预订整个套餐,则进行预订编排的流程知道取消房间预订。
您可以通过将所有计划移动到一个集合中来简化事情;将一致性边界提高到更大的范围(可能 属性,而不是单个房间);这牺牲了更大房间的自主权和规模。
几乎所有包含资源调度的域模型都将日作为单独的聚合概念。没有它,你将永远聚集在一起。不同的上下文可以保留不同的日期表示:
- 预订可以有房型和空房情况
- 定价可以有房型和价格
- 接待处可以分配房间、到达和离开