我有下表:
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
。
答案 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();