所以你有这样的类:
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));