【问题标题】:Filter rows before .ToList() using LINQ and Entity Framework使用 LINQ 和实体框架过滤 .ToList() 之前的行
【发布时间】:2020-06-20 09:12:03
【问题描述】:

我有一些桌子:

通知队列

NotQueueId OrderId CreateDateTime      SentDateTime NotType
1          Order1  2020-02-25 10:37:17 NULL         Failure
2          Order1  2020-02-25 16:37:18 NULL         Escalation
3          Order2  2020-02-24 04:37:16 NULL         Failure
4          Order2  2020-02-24 10:37:17 NULL         Escalation
5          Order3  2020-02-26 10:30:17 NULL         Failure
6          Order4  2020-02-26 10:10:17 NULL         Failure
7          Order4  2020-02-26 16:10:18 NULL         Escalation
8          Order5  2020-02-26 10:10:17 NULL         Failure

失败的票

FailedTicketId OrderId StatusId FailedReason     CreateDateTime      UpdateDateTime
1              Order1  2        Somereason1      2020-02-25 10:37:17 NULL
2              Order2  3        Somereason2      2020-02-24 04:37:16 NULL
2              Order3  3        Somereason3      2020-02-26 10:30:17 NULL
2              Order4  5        Cancelled        2020-02-26 10:10:17 2020-02-27 16:10:18
2              Order5  4        Succeeded Later  2020-02-26 10:10:17 2020-02-25 01:37:16

状态

StatusId StatusDESC
1        Initial
2        Validated
3        Saved
4        Complete
5        Cancelled

基本上这里发生的事情是:

  1. 每次故障单失败时,它都会被推送到 FailedTickets 表,同时也被推送到 NotificationQueue 表并停留在那里,以便一些 电子邮件发送作业 将接收它并发送电子邮件并更新 SendDateTime 列。
  2. 在 6 小时内未解决工单后,将向 NotificationQueue 表推送新行,指示需要升级工单。

我需要的输出是:

  1. 请勿退回任何已取消已完成的票。
  2. 如果相同的 OrderId 已进入 Escalation,则完全跳过为 Failure 生成的行,仅返回 Escalation 行。
  3. 退回所有失败的票证(如果尚未升级)。

使用上述表格和标准的示例输出:

NotType    OrderId Status    FailedReason CreateDateTime      NotQueueId SentDateTime
Escalation Order1  Validated Somereason1  2020-02-25 16:37:18 2          NULL
Escalation Order2  Saved     Somereason2  2020-02-24 10:37:17 4          NULL
Failure    Order3  Saved     Somereason3  2020-02-26 10:30:17 5          NULL

但目前我只能做到这一点:

NotType    OrderId Status    FailedReason CreateDateTime      NotQueueId SentDateTime
Failure    Order1  Validated Somereason1  2020-02-25 10:37:17 1          NULL
Escalation Order1  Validated Somereason1  2020-02-25 16:37:18 2          NULL
Failure    Order2  Saved     Somereason2  2020-02-24 04:37:16 3          NULL
Escalation Order2  Saved     Somereason2  2020-02-24 10:37:17 4          NULL
Failure    Order3  Saved     Somereason3  2020-02-26 10:30:17 5          NULL

使用此代码:

var skippableStatuses = new List<string> { "Complete", "Cancelled" };
var failedAndEscalatedRows = (from nq in somedbContext.NotificationQueues
               join ft in somedbContext.FailedTickets on nq.OrderID equals ft.OrderID
               join s in somedbContext.Statuses on ft.StatusID equals os.StatusID
               select new
               {
                   CreatedDate = nq.CreateDatetime,
                   NotificationType = nq.NotType,
                   NotQueueId = nq.NotQueueId,
                   OrderId = nq.OrderId,
                   SentTime = nq.SentDateTime,
                   Reason = ft.FailedReason,
                   Status = s.StatusDESC
               }
           ).Where(e => !skippableStatuses.Contains(e.Status)).ToList();

现在我可能可以遍历这些记录并检索具有 Escalation 状态的记录。 但我不想返回我什至不需要的行,所以在调用 .ToList() 之前,我想创建一个 LINQ 查询以仅返回所需的行并完全避免循环。

我确信必须有更好的方法来做到这一点,所以我转向了 SO!

【问题讨论】:

    标签: c# sql .net entity-framework linq


    【解决方案1】:

    您需要的是,在进行任何联接之前对您的第一个表的数据 (NotificationQueues) 进行一些过滤和分组,如下所示:

     var failedAndEscalatedRows = 
    
        (from nq in somedbContext.NotificationQueues.GroupBy(c => c.OrderId).Select(c => new
        {
             c.Key,
             CreateDatetime = c.Select(d => d.CreateDateTime).FirstOrDefault(),
             NotQueueId = c.Select(d => d.NotQueueId).FirstOrDefault(),
             NotType = c.Count() > 1 ? c.FirstOrDefault(d => d.NotType == "Escalation").NotType 
                 : c.FirstOrDefault(d => d.NotType == "Failure").NotType,
             SentDateTime = c.Select(d => d.SentDateTime).FirstOrDefault()
        })
    
            join ft in somedbContext.FailedTickets on nq.Key equals ft.OrderId
            join s in somedbContext.Statuses on ft.StatusId equals s.StatusId
            select new
            {
                CreatedDate = nq.CreateDatetime,
                NotificationType = nq.NotType,
                NotQueueId = nq.NotQueueId,
                OrderId = nq.Key,
                SentTime = nq.SentDateTime,
                Reason = ft.FailedReason,
                Status = s.StatusDESC
            }
        ).Where(e => !skippableStatuses.Contains(e.Status)).ToList();
    

    【讨论】:

    • 嗨 Salah,谢谢您的回答,但我正在寻找的是,在任何给定时间,工单都可能处于失败状态或升级状态,如果升级,我想要整个升级行,而不仅仅是NotType
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-06-18
    相关资源
    最近更新 更多