【问题标题】:Linq2Entities query to find records given mix-max rangeLinq2Entities 查询以查找给定 mix-max 范围的记录
【发布时间】:2019-06-02 18:39:13
【问题描述】:

我有这两个实体:

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 实体保存有关StopId 和Order 的信息,在公共汽车旅行期间访问它。所以基本上,重叠的车票在某些时候会有相同的Order 号码(除非它是最后一站,这意味着乘客要离开公共汽车)。

所以我拥有的是LineId、ScheduleId、StartId 和EndId,其中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

 }

但是obs。这不是LINQ 的工作方式。那么如何找到该范围重叠的所有票证呢?

【问题讨论】:

    标签: c# linq-to-entities


    【解决方案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);
    

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

    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));
    

    【讨论】:

    • 这就是我想要的。它认为我自己弄清楚了,但如果你有时间,还有一个问题。在分组和过滤之后,我想在这些条件下采用实际的SeatIds。写法是否正确:.Select(tg =&gt; tg.First().Ticket.SeatId) 它似乎返回了正确的结果,但正如您所见,我对 LINQ\GroupBy 不熟悉。无论如何,谢谢。
    • 看来您将在tg 组中拥有多张票 - 所有SeatId 是否都相同,或者您需要决定返回哪个票?这肯定会奏效,但它只会以(可能)随机顺序返回第一个匹配项。
    • 是的,我想通了。 SeatIds 是不同的,因此仅获得一个是不够的,但 GroupBy 方法是 IMO 的方法。然而,由于它是我实现中最重要的部分之一,我决定在Ticket 实体中也包含最小/最大顺序,这使结构非规范化,但使其更易于使用。所以现在我不会为此付出更多的努力。如果您有兴趣,我会很感激GroupBy 的解决方案,其中所有SeatIds 都会返回。
    • @Leron 这很简单 - 您只需从每个组中选择它们。我使用SelectMany 撤消该组,但您也可以嵌套Select,然后再使用First()。 LINQ to Entities 可能能够相互转换。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-02-22
    • 1970-01-01
    • 1970-01-01
    • 2020-05-21
    • 1970-01-01
    • 2017-02-28
    相关资源
    最近更新 更多