在开始和结束日期时间过滤(预订)项目

Posted

技术标签:

【中文标题】在开始和结束日期时间过滤(预订)项目【英文标题】:Filter (reservation) items on start and end DateTime 【发布时间】:2021-12-09 02:26:06 【问题描述】:

我是 .NET-Core 和构建 API 的新手,但遇到了一个问题。 我正在制作一个(android)应用程序,人们可以在其中计划活动/生日派对或其他东西。 用户可以在填写开始和结束日期/时间后检索可用(预先添加的)场地/位置列表。这是我卡住的部分。

在他们填写开始和结束日期后,我想要一份可用场地列表,仅显示他们所选时间段的可用场地。

我的 API 中有 2 个模型,一个“Venue”模型和一个“VenueReservation”模型。

Venue 模型有一个 ID、位置和名称。 VenueReservationModel 有一个 Id、venueId、startDateTime、endDateTime。

我可以使用或做什么来根据用户的 DateTime 输入(开始和结束 DateTime)检索可用场所?

我使用 Enumerable.Where 方法玩弄 LINQ,但似乎找不到答案。

提前致谢!

【问题讨论】:

请提供足够的代码,以便其他人更好地理解或重现问题。 【参考方案1】:

所以你有这样的类:

class Venue

    public int Id get; set;
    public string Location get; set;
    public string Name get; set;


class VenueReservation

    public int Id get; set;
    public int VenueId get; set;             // foreign key to Venue
    public DateTime StartDateTime get; set;
    public DateTime EndDateTime get; set;

你有:

IQueryable<Venue> Venues => ...        // Probably DbSet<Venue>
IQueryable<VenueReservation> VenueReservations => ...

在他们填写开始和结束日期后,我想要一份可用场地列表,仅显示他们所选时间段的可用场地。

因此,您需要获取“具有零个或多个 VenueReservations 的场地”。一旦你得到它们,你就可以只保留那些在所选时间段内根本没有预订的场地。

通过他们的预订获取场地

通常要获得“具有零个或多个 VenueReservations 的场地”,我会使用 Queryable.GroupJoin。有人提到.net core 不支持 GroupJoin。在这种情况下,请使用左外连接,后跟 GroupBy:

var venuesWithTheirReservations = venues.GroupJoin(venueReservations,

    venue => venue.Id,                            // from every Venue take the Id
    venueReservation => venueReservation.VenueId, // from every Reservation take the foreign key

    (venue, reservationsForThisVenue) => new
    
        Venue = venue,
        Reservations = reservationsForThisVenue,
    );

或LINQ left outer join 后跟 GroupBy:

var venuesWithTheirReservations = from venue in venues
    join reservation in venueReservations
    on venue.Id equals reservation.VenueId into g
    from reservationForThisVenu in g.DefaultIfEmpty()
    select new
    
        Venue = venue,
        Reservation = reservationForThisVenue,
    )
    .GroupBy(joinResult => joinResult.Venue,

    // parameter resultSelector: for every venue, and all reservations for this venue
    // make one new
    (venue, reservationsForThisVenue) => new
    
        Venue = venue,
        Reservations = reservationsForThisVenue,
    );

只保留可用的场地

所以,现在您已经获得了场地,每个场地都有预订,您可以使用Queryable.Where 仅保留在时间段内根本没有预订的场地。

换句话说:任何保留都不应与时隙重叠。

所有预订都应在时隙开始之前结束 (= 完整的预订在时间段之前) 或在时隙结束后开始 (= 完整的预订在时间段之后。

我们不希望部分时间段内的预订

所以继续 LINQ:

DateTime timeSlotStart = ...
DateTime timeSlotEnd = ...

var availableVenues = venuesWithTheirReservations.Where(venue =>

    // every Reservation should end before timeSlotStart
    // OR start after the timeSlotEnd:
    venue.Reservations.All(reservation =>

        // end before timeSlotStart OR
        reservation.EndDateTime <= timeSlotStart ||

        // start after the timeSlotEnd:
        reservation.StartDatetime >= timeSlotEnd));

【讨论】:

感谢您的解释!它帮助很大,这就是我正在寻找的。再次感谢!【参考方案2】:

你可以这样做。

获取在开始和结束之间输入日期的预订

IEnumerable<VenueReservation> reservationsBetweenStartAndEnd = venueReservations
    .Where(x => inputDateTime > x.StartDateTime && inputDateTime < x.EndDateTime);

获取输入日期在开始和结束之外的预订

IEnumerable<VenueReservation> reservationsOutsideStartAndEnd = venueReservations
    .Where(x => inputDateTime < x.StartDateTime || inputDateTime > x.EndDateTime);

如果您想严格比较日期并减少小时和分钟,您可以简单地在 DateTime 上使用 .Date。

举个例子,你会这样做

IEnumerable<VenueReservation> reservationsBetweenStartAndEnd = venueReservations
    .Where(x => inputDateTime.Date > x.StartDateTime.Date && inputDateTime.Date < x.EndDateTime.Date);

【讨论】:

【参考方案3】:

还有

List<VenueReservation> reservationsBetweenStartAndEnd = venueReservations
    .Where(x => inputDateTime.Date > x.StartDateTime.Date && inputDateTime.Date < x.EndDateTime.Date).toLis();

【讨论】:

以上是关于在开始和结束日期时间过滤(预订)项目的主要内容,如果未能解决你的问题,请参考以下文章

CakePHP 在 2 个日期记录之间搜索

Spark Window Functions:过滤掉开始和结束日期在另一行开始和结束日期范围内的行

SQL, SELECT 特定日期未预订的项目

查询可预订的车辆

开始日期结束日期列上的 JSON Linq.js 过滤器

SQL 日期过滤器:当开始日期 = 结束日期时返回结果