У меня есть следующая таблица:
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
2
и 4
, потому что последнее состояние (хронологическое и по DateTime) равно 10
или 8
.Счета с идентификатором 1
не годятся, потому что последнее состояние 1
, 3
последнее состояние 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.
Я пытался:
//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();
//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();
//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?

Для упрощения
Я хотел бы получить все InvoiceIds
, которыепоследнее состояние 8
или 10
.
