Cannot在包含聚合或子查询
的表达式上执行聚合函数我有预订,每种都有多次付款尝试,我只想选择最新的付款尝试,然后总和所有这些付款金额。
var query =
from reservation in DbContext.Reservations
join p1 in DbContext.Payments on reservation.Id equals p1.ReservationId into p2
let payment = p2.OrderByDescending(x => x.Id).FirstOrDefault()
orderby reservation.Id descending
select new ReservationPaymentReport
{
ReservationId = reservation.Id,
PaymentId = payment != null ? payment.Id : (int?)null,
PaymentAmount = payment != null ? payment.Amount : (decimal?)null,
IsPaymentCompleted = payment != null && paymentCompletedStatusIds.Contains(payment.StatusId),
};
然后我使用该基本查询进行最终计算:
var paymentTotal = query
.Where(x => x.PaymentId != null && x.IsPaymentCompleted.Value)
.Sum(x => x.PaymentAmount) ?? 0;
我应该在哪里进行重组/优化以使其正常工作? update:
这是EF6生产的SQL,它使用
CROSS APPLY
正常工作。我已经清理了它并取代了可读性:
SELECT
SUM(Filter3.PaymentTotal) AS PaymentTotal
FROM
(
SELECT CASE WHEN p2.Id IS NOT NULL THEN p2.Amount END AS PaymentTotal
FROM (SELECT Id FROM dbo.Reservations) AS r
OUTER APPLY
(
SELECT TOP 1 p1.Id, p1.Amount, p1.StatusId
FROM
(
SELECT p.Id, p.Amount, p.StatusId
FROM dbo.Payments AS p
WHERE r.Id = p.ReservationId
) AS p1
ORDER BY p1.Id DESC
) AS p2
WHERE
(
CASE WHEN (p2.Id IS NOT NULL) THEN p2.Id END IS NOT NULL
)
AND
(
(
CASE
WHEN (p2.Id IS NOT NULL AND p2.StatusId IN (6, 9, 7) AND p2.StatusId IS NOT NULL) THEN cast(1 as bit)
WHEN ( NOT (p2.Id IS NOT NULL AND p2.StatusId IN (6, 9, 7) AND p2.StatusId IS NOT NULL)) THEN cast(0 as bit)
END
) = 1
)
) AS Filter3
SELECT COALESCE
(
SUM((
SELECT TOP 1 p2.Amount
FROM Payments AS p2
WHERE r.Id = p2.ReservationId
ORDER BY p2.Id DESC)), 0.0
)
FROM Reservations AS r
WHERE
((
SELECT TOP 1 p.Id
FROM Payments AS p
WHERE r.Id = p.ReservationId
ORDER BY p.Id DESC
) IS NOT NULL)
AND EXISTS
(
SELECT 1
FROM Payments AS p0
WHERE r.Id = p0.ReservationId
)
AND
(
SELECT TOP 1 p1.StatusId
FROM Payments AS p1
WHERE r.Id = p1.ReservationId
ORDER BY p1.Id DESC
) IN (6, 9, 7)
这是EF Core 8及以下的已知缺失功能,现在已经通过EF 9进行了支持。 Github上的门票跟踪了该功能的开发:https://github.com/dotnet/efcore/issues/34256