Мне нужен такой простой, простой запрос, он удаляет меня, сколько работы я сделал, просто пытаясь сделать это в LINQ. В T-SQL, это было бы:LINQ aggregate left join on SQL CE
SELECT I.InvoiceID, I.CustomerID, I.Amount AS AmountInvoiced,
I.Date AS InvoiceDate, ISNULL(SUM(P.Amount), 0) AS AmountPaid,
I.Amount - ISNULL(SUM(P.Amount), 0) AS AmountDue
FROM Invoices I
LEFT JOIN Payments P ON I.InvoiceID = P.InvoiceID
WHERE I.Date between @start and @end
GROUP BY I.InvoiceID, I.CustomerID, I.Amount, I.Date
ORDER BY AmountDue DESC
Лучшее выражение эквивалентно LINQ Я придумал, взял меня гораздо больше времени, чтобы сделать:
var invoices = (
from I in Invoices
where I.Date >= start &&
I.Date <= end
join P in Payments on I.InvoiceID equals P.InvoiceID into payments
select new{
I.InvoiceID, I.CustomerID, AmountInvoiced = I.Amount, InvoiceDate = I.Date,
AmountPaid = ((decimal?)payments.Select(P=>P.Amount).Sum()).GetValueOrDefault(),
AmountDue = I.Amount - ((decimal?)payments.Select(P=>P.Amount).Sum()).GetValueOrDefault()
}
).OrderByDescending(row=>row.AmountDue);
Это получает эквивалентный набор результатов при запуске против SQL Server. Однако использование базы данных SQL CE изменяет ситуацию. T-SQL остается почти таким же. Мне нужно только изменить ISNULL
на COALESCE
. Используя те же выражения LINQ, однако, приводит к ошибке:
There was an error parsing the query. [ Token line number = 4, Token line offset = 9,Token in error = SELECT ]
Так мы посмотрим на сгенерированный код SQL:
SELECT [t3].[InvoiceID], [t3].[CustomerID], [t3].[Amount] AS [AmountInvoiced], [t3].[Date] AS [InvoiceDate], [t3].[value] AS [AmountPaid], [t3].[value2] AS [AmountDue]
FROM (
SELECT [t0].[InvoiceID], [t0].[CustomerID], [t0].[Amount], [t0].[Date], COALESCE((
SELECT SUM([t1].[Amount])
FROM [Payments] AS [t1]
WHERE [t0].[InvoiceID] = [t1].[InvoiceID]
),0) AS [value], [t0].[Amount] - (COALESCE((
SELECT SUM([t2].[Amount])
FROM [Payments] AS [t2]
WHERE [t0].[InvoiceID] = [t2].[InvoiceID]
),0)) AS [value2]
FROM [Invoices] AS [t0]
) AS [t3]
WHERE ([t3].[Date] >= @p0) AND ([t3].[Date] <= @p1)
ORDER BY [t3].[value2] DESC
тьфу! Хорошо, так что он уродлив и неэффективен при работе с SQL Server, но мы не должны заботиться о нем, так как это Предполагалось, что будет быстрее напишите, а разница в производительности не должна быть такой большой. Но это просто не работает против SQL CE, который, по-видимому, не поддерживает подзапросы в списке SELECT.
На самом деле, я пробовал несколько разных запросов левого соединения в LINQ, и все они, похоже, имеют одинаковую проблему. Даже:
from I in Invoices
join P in Payments on I.InvoiceID equals P.InvoiceID into payments
select new{I, payments}
генерирует:
SELECT [t0].[InvoiceID], [t0].[CustomerID], [t0].[Amount], [t0].[Date], [t1].[InvoiceID] AS [InvoiceID2], [t1].[Amount] AS [Amount2], [t1].[Date] AS [Date2], (
SELECT COUNT(*)
FROM [Payments] AS [t2]
WHERE [t0].[InvoiceID] = [t2].[InvoiceID]
) AS [value]
FROM [Invoices] AS [t0]
LEFT OUTER JOIN [Payments] AS [t1] ON [t0].[InvoiceID] = [t1].[InvoiceID]
ORDER BY [t0].[InvoiceID]
, который также приводит к ошибке:
There was an error parsing the query. [ Token line number = 2, Token line offset = 5,Token in error = SELECT ]
Так как я могу сделать простой левый присоединиться в базе данных SQL CE с помощью LINQ? Я трачу свое время?
Ваше первое решение без 'DefaultIfEmpty()' взорвано аналогичной ошибкой, как и мои примеры. Ваш второй пример работает! Спасибо! Я попробую эту технику и в других моих попытках присоединиться. –