LINQ aggregate left join on SQL CE

Posted by P Daddy on Stack Overflow See other posts from Stack Overflow or by P Daddy
Published on 2009-08-15T17:35:48Z Indexed on 2010/04/27 3:33 UTC
Read the original article Hit count: 341

Filed under:
|
|
|

What I need is such a simple, easy query, it blows me away how much work I've done just trying to do it in LINQ. In T-SQL, it would be:

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

The best equivalent LINQ expression I've come up with, took me much longer to do:

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);

This gets an equivalent result set when run against SQL Server. Using a SQL CE database, however, changes things. The T-SQL stays almost the same. I only have to change ISNULL to COALESCE. Using the same LINQ expression, however, results in an error:

There was an error parsing the query. [ Token line number = 4,
Token line offset = 9,Token in error = SELECT ]

So we look at the generated SQL code:

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

Ugh! Okay, so it's ugly and inefficient when run against SQL Server, but we're not supposed to care, since it's supposed to be quicker to write, and the performance difference shouldn't be that large. But it just doesn't work against SQL CE, which apparently doesn't support subqueries within the SELECT list.

In fact, I've tried several different left join queries in LINQ, and they all seem to have the same problem. Even:

from I in Invoices
join P in Payments on I.InvoiceID equals P.InvoiceID into payments
select new{I, payments}

generates:

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]

which also results in the error:

There was an error parsing the query. [ Token line number = 2,
Token line offset = 5,Token in error = SELECT ]

So how can I do a simple left join on a SQL CE database using LINQ? Am I wasting my time?

© Stack Overflow or respective owner

Related posts about c#

Related posts about LINQ