几个月前,我改进了我们的可用性引擎,以便将我们的逻辑从数据库转移到微服务。当时的业务逻辑还算简单:
一个资源(会议室、办公桌、空办公室、设备)只有在尚未被预订的情况下才在给定的时间范围内可用(即:没有其他使用相同资源的预订)
当资源不可用时,必须计算最接近的可用时间范围
为了满足这些要求,我构建了下面的一小段代码:
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
(...)
}
我不觉得这个解决方案真的很优雅。对我来说,更好的解决方案是检索时间表并将它们组合起来以确定实际可用性。我尝试了几种解决方案,但最终编写了意大利面条代码。
您对我如何重新设计聚合以正确处理这个新概念有什么想法吗?
谢谢你,塞布