如何确定组合房间可用性DDD

时间:2017-10-07 13:38:05

标签: .net domain-driven-design availability

我几个月前改进了我们的可用性引擎,以便将我们的逻辑从数据库转移到微服务。那时,业务逻辑非常简单:

  • 资源(会议室,办公桌,空办公室,设备)仅在给定时间范围内可用(如果尚未预订)(即:不使用相同资源进行其他预订)

  • 当资源不可用时,必须计算最接近的可用时间范围

为了满足这些要求,我在下面构建了一小段代码:

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

2 个答案:

答案 0 :(得分:1)

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

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

因此,包的可用性很容易 - 采用包中元素的时间表的交集。由于您知道包的内容,因此很容易找到协调所需的计划。

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

当然,你必须弄明白你将如何处理多个房间的实际预订。有几种可能性;最简单的,也就是我猜测的用户最熟悉的是,允许时间表聚合接受重叠预订,设置双重预订标记以跟踪需要采取补偿措施的情况。

另一种选择是使用传奇模式预订包裹;如果无法预订整个套餐,那么进行预订编排的流程会知道取消预订房间。

您可以通过将所有计划移动到单个聚合中来简化操作;将一致性边界提升到更大的范围(可能是财产,而不是单个房间);这会影响较大房间的自治和规模。

答案 1 :(得分:0)

几乎所有包含资源调度的域模型都将Day作为单独的聚合概念。没有它,你将永远聚合。不同的背景可以保持一天的不同表现形式:

  • 预订可以有房型和可用性
  • 定价可以有房型和价格
  • 接待处可以分配房间,到达和离开