Linq2Entities查询以找到具有给定最大混合范围的记录

时间:2019-06-02 18:39:13

标签: c# linq-to-entities

我有这两个实体:

public class Ticket
{
    public int Id { get; set; }
    public int ScheduleId { get; set; }
    public int SeatId { get; set; }

    [DataType(DataType.Date)]
    [Column(TypeName = "Date")]
    [DisplayFormat(DataFormatString = "{0:yyyy-MM-dd}", ApplyFormatInEditMode = true)]
    public DateTime ForDate { get; set; }

    public Seat Seat { get; set; }
    public Schedule Schedule { get; set; }
    public ICollection<TicketStop> TicketStops { get; set; }
}

public class TicketStop
{
    public int Id { get; set; }
    public int TicketId { get; set; }
    public int LineStopStationId { get; set; }

    public Ticket Ticket { get; set; }
    public LineStopStation LineStopStation { get; set; }
}

public class LineStopStation
{
    public int Id { get; set; }
    public int LineId { get; set; }
    public int StopId { get; set; }
    public int Order { get; set; }
    public bool IsLastStop { get; set; }

    public Line Line { get; set; }
    public Stop Stop { get; set; }
}

业务案例是我正在实施公交车票预订系统(主要用于学习),并且我想查找重叠的车票。

LineId + ScheduleId + ForDate的组合唯一地标识了一张票是在特定日期和出发时间针对特定公共汽车的。

我要解决的问题是,根据起始和结束位置,确定两张票是否在一个或多个停靠点重叠。

LineStopStation实体保存有关StopIdOrder的信息,该信息在公共汽车旅行期间在其中被访问。因此,基本上,重叠的票在某个点将具有相同的Order号(除非它是最后一站,这意味着乘客要离开公共汽车)。

所以我拥有的是LineIdScheduleIdStartIdEndId,其中starId和endId对应于LineStopStation.StopId,所以最终我可以得到像这样从他们那里订购。

        int startStationOrder = _context.LineStopStations
            .First(l => l.LineId == lineId && l.StopId == startId).Order;

        int endStationOrder = _context.LineStopStations
            .First(l => l.LineId == lineId && l.StopId == endId).Order;

因此,我非常确信,拥有所有这些信息后,我应该能够找到在TicketStop表中是否有与相关数据重叠的票证。 TicketStop以这种方式工作-如果有人买了3站的票,我将在那里拥有相同的TicketId和三个不同的LineStopStationId的三个记录。

我觉得这个问题超出了需要。所以基本上我有这个:

 public List<Seat> GetAvailableSeats(int lineId, int scheduleId, int startId, int endId, DateTime forDate)
 {
   int startStationOrder = _context.LineStopStations
       .First(l => l.LineId == lineId && l.StopId == startId).Order;

   int endStationOrder = _context.LineStopStations
       .First(l => l.LineId == lineId && l.StopId == endId).Order;

   var reservedSeats = _context.TicketStops
       .Where(t => t.Ticket.ScheduleId == scheduleId)
       .Where(t => t.Ticket.ForDate == forDate)
       //basically I don't know how to proceed here.
       //In pseudo code it should be something like:
       .Where(t => t.Min(Order) >= endStationOrder || t.Max(Order) <= startStationOrder

 }

但是。 LINQ的工作方式并非如此。那么如何查找此范围重叠的所有票证?

1 个答案:

答案 0 :(得分:1)

如果不对模型进行深入分析,也许这样的事情可能会给您一个想法?

var reservedSeats = _context.TicketStops
                            .GroupBy(t => new { t.Ticket.ScheduleId, t.Ticket.ForDate })
                            .Where(tg => tg.Key == new { ScheduleId = scheduleId, ForDate = forDate })
                            .Where(tg => tg.Min(t => t.LineStopStation.Order) >= endStationOrder || tg.Max(t => t.LineStopStation.Order) <= startStationOrder);

您还可以先过滤并做一个空的GroupBy

var reservedSeats = _context.TicketStops
                            .Where(t => t.Ticket.ScheduleId == scheduleId && t.Ticket.ForDate == forDate)
                            .GroupBy(t => 1)
                            .Where(tg => tg.Min(t => t.LineStopStation.Order) >= endStationOrder || tg.Max(t => t.LineStopStation.Order) <= startStationOrder);

要返回所有SeatId,只需从组中选择它们即可。

var reservedSeats = _context.TicketStops
                            .Where(t => t.Ticket.ScheduleId == scheduleId && t.Ticket.ForDate == forDate)
                            .GroupBy(t => 1)
                            .Where(tg => tg.Min(t => t.LineStopStation.Order) >= endStationOrder || tg.Max(t => t.LineStopStation.Order) <= startStationOrder);
                            .SelectMany(tg => tg.Select(t => t.Ticket.SeatId));