2017-10-07 58 views
0

为了将我们的逻辑从数据库迁移到微服务,我在几个月前修改了可用性引擎。当时,业务逻辑是相当简单:如何确定组合房间的可用性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() { } 
} 

几周前,我被要求处理组合房间(两个较小的房间可以合并成一个更大的组合房间)。在这种情况下,组合房间只能使用其子房间和本身。换句话说,我需要检查几个时间表来确定可用性,不幸的是,我当前的抽象级别不允许(一个时间表,一个房间)。

我发现的唯一方法是检索资源及其子(= subrooms),然后创建一个包含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 

    (...) 
} 

我不觉得这个解决方案真的很优雅。对我来说,更好的解决方案是检索计划并将它们合并以确定实际可用性。我尝试了几种解决方案,但最终我写了意大利面代码。

对于如何重新设计我的聚合以正确处理这个新概念,您有什么想法吗?

谢谢 勒布

+0

有没有提前知道有限的子房可能性,还是可以将任何两个房间组合成一个更大的房间? – guillaume31

+0

是的,他们提前知道。我知道哪些房间可以合并。其实我把这个信息存储在一个分贝:) – Seb

回答

1

在猜测,核心的问题是,你缺少域概念模型。

我的猜测是,您遗漏了描述可用库存的产品目录的表示。在该目录中,您将获得101号房间入口和102号房间入口。如果这些房间可以打包在一起,那么您还可以输入包裹[#101和#102]。

因此,软件包的可用性很容易 - 将软件包中元素的时间表交叉。既然你知道包的内容,很容易找到你需要调和的时间表。

请注意,您可以更新目录 - 添加或删除软件包 - 不以任何方式影响预订。

你当然必须弄清楚你将如何处理多个房间的实际预订。有几种可能性;最简单的一个,我猜想你的用户最熟悉的是允许计划汇总接受重叠预订,设置一个双重预订标志来跟踪需要采取补偿行动的情况。

另一种选择是使用saga模式预订软件包;如果无法预订整个包裹,则执行预订编排的过程知道取消预订房间。

您可以通过将所有日程表移动到单个聚合中来简化操作;将一致性边界扩大到更大规模(可能属性,而不是单个房间);这剥夺了较大房间的自主性和规模。

+0

谢谢你这个有用的答案。我将修改我的模型以添加这个包的概念。如果我理解正确,你可以得到一个包的时间表,而不是单个资源。我对么?此外,可用性引擎还处于“微服务”状态,不知道如何取消/预订。它只用于实际获得资源的可用性。 – Seb

0

几乎任何包含资源调度的域模型都将Day的概念视为单独的聚合。没有它,你将永远保持聚合。不同的上下文可以保持一天中的不同表现:

  • 预订可以有房类型和可用性
  • 定价可以有房型和价格
  • 接待可以有房分配,抵港及离港