EF Core转换为MAX(Last)GROUP BY,LINDS和WHERE的LINQ混合

时间:2018-10-08 12:28:57

标签: entity-framework linq entity-framework-core

我有下表:

Id   DateTime      UserId  InvoiceId  State
1    2018-01...    1       1          5
2    2018-02...    2       1          2
3    2018-03...    2       1          1
4    2018-01...    2       2          5
5    2018-02...    1       2          8
6    2018-01...    1       3          5
7    2018-02...    2       3          8
8    2018-03...    1       3          5
9    2018-04...    2       3          10
10   2018-05...    2       3          5
11   2018-01...    1       4          1
11   2018-02...    2       4          10

我想获得InvoiceId 24,因为最后一个状态(按时间顺序并按DateTime)是108。 标识为1的发票不好,因为最后一个状态为13的最后一个状态为5

这两个查询均返回正确的结果:

SELECT [t].[InvoiceId]
FROM [Postman].[Invoice-States] AS [t]
INNER JOIN [Postman].[Invoices] AS [t.Invoice] ON [t].[InvoiceId] = [t.Invoice].[Id]
INNER JOIN [Postman].[Recipients] AS [t.Invoice.Recipient] ON [t.Invoice].[RecipientId] = [t.Invoice.Recipient].[Id]
WHERE [t.Invoice.Recipient].[PartnerId] = 4
GROUP BY [t].[InvoiceId], [t].[DocumentState]
HAVING (MAX([t].[InsertedDateTime]) = (select top 1 InsertedDateTime from [Postman].[Invoice-States]  where t.InvoiceId = InvoiceId order by InsertedDateTime desc)) AND [t].[DocumentState] IN (CAST(8 AS tinyint), CAST(10 AS tinyint))

SELECT RES.[InvoiceId] FROM [Postman].[Invoice-States] AS RES
INNER JOIN (
SELECT [t].[InvoiceId], Max([t].[InsertedDateTime]) AS MaxInsertedDateTime
  FROM [OpPIS.Web.Development.Opal].[Postman].[Invoice-States] AS [t]
  INNER JOIN [OpPIS.Web.Development.Opal].[Postman].[Invoices] AS [t.Invoice] ON [t].[InvoiceId] = [t.Invoice].[Id]
  INNER JOIN [Postman].[Recipients] AS [t.Invoice.Recipient] ON [t.Invoice].[RecipientId] = [t.Invoice.Recipient].[Id]
  WHERE [t.Invoice.Recipient].[PartnerId] = 4
  GROUP BY [t].[InvoiceId]) AS MD
ON RES.InvoiceId = MD.InvoiceId AND RES.[InsertedDateTime] = MD.MaxInsertedDateTime AND (RES.DocumentState IN (8, 10))

但是我不知道如何翻译成LINQ。
我尝试过:

  1.     //Returns ALL that have 8 or 10.
        var fDocsState = await this.Query<DbInvoiceState>(t => t.Invoice.Recipient.PartnerId == partnerId)
            .GroupBy(t => t.InvoiceId, t => new { t.DocumentState, t.InsertedDateTime })
            .Where(t => states.Contains(t.OrderByDescending(t2 => t2.InsertedDateTime).Select(t2 => t2.DocumentState).FirstOrDefault()))
            .Select(t => t.Key)
            .ToListAsync();
    
  2.     //Column 'Postman.Invoice-States.DocumentState' is invalid in the select list because it is not contained in either an aggregate function or the GROUP BY clause.
        var fDocsState = await this.Query<DbInvoiceState>(t => t.Invoice.Recipient.PartnerId == partnerId)
            .GroupBy(t => t.InvoiceId, (key, t) => states.Contains(t.Last().DocumentState))
            .ToListAsync();
    
  3.     //Exception in LINQ
        var fDocsState = await this.Query<DbInvoiceState>(t => t.Invoice.Recipient.PartnerId == partnerId)
            .GroupBy(t => t.InvoiceId, (key, t) => t.Last())
            .Where(t => states.Contains(t.DocumentState))
            .ToListAsync();
    

这会返回正确的结果,但是会在本地进行评估(性能不佳)。

    var fDocsState = await this.Query<DbInvoiceState>(t => t.Invoice.Recipient.PartnerId == partnerId)
        .GroupBy(t => t.InvoiceId)
        .Select(t => new
        {
            t.Key,
            DocumentState = t.OrderByDescending(t2 => t2.InsertedDateTime).Select(t2 => t2.DocumentState).FirstOrDefault()
        })
        .ToListAsync();

还有其他想法,如何使用EF Core获得理想的结果?

Screenshot

为简化

我想获得所有InvoiceIds,最后一个状态为810

screenshot

1 个答案:

答案 0 :(得分:0)

找到它,如何使用包含进行内部连接

    var states = new[] { DocumentState.ConfirmedReceive, DocumentState.ReceiverConfirm, DocumentState.ReceiverRefused };

    return await this.Set<DbInvoiceState>().Join(
            this.Set<DbInvoiceState>().GroupBy(t => t.InvoiceId).Select(t => new { t.Key, MaxInserted = t.Max(t2 => t2.InsertedDateTime) }),
            t => new
            {
                t.InvoiceId,
                t.InsertedDateTime,
                states = states.Contains(t.DocumentState)
            },
            t => new
            {
                InvoiceId = t.Key,
                InsertedDateTime = t.MaxInserted,
                states = true
            },
            (t, t2) => new ViewInvoiceListModel
            {
                Id = t2.Key
            })
        .ToArrayAsync();