Question

I'm trying to generate following report from popular NorthWind DB using Linq. It should be group by Customer, OrderYear.

CustomerName    OrderYear    Amount

I've to use the following tables Customer,Order and Order Details. So far this is what I've done.

NorthwindDataContext north = new NorthwindDataContext();

        var query = from o in north.Orders
                    group o by o.Customer.CompanyName  into cg
                    select new
                    {
                        Company = cg.Key,
                        YearGroup = (   from y in cg
                                              group y by y.OrderDate.Value.Year into yg
                                              select new 
                                              {
                                                  Year = yg.Key,
                                                  YearOrdes = yg
                                              }                                             
                                         )
                    };


        foreach (var q in query)
        {
            Console.WriteLine("Customer Name : " + q.Company);
            foreach (var o in q.YearGroup)
            {
                Console.WriteLine("Year " + o.Year);
                Console.WriteLine("Sum " + o.YearOrdes.Sum(yo => yo.Order_Details.Sum( yd=> Convert.ToDecimal(yd.UnitPrice* yd.Quantity))));           
            }

            Console.WriteLine();
        }

It is giving me expected results. I compared by running t-sql in back end.But, I've 2 questions.

  1. In the Inner foreach, the 2nd statement generate the sum. Is it proper approach? Or there is better one available?
  2. How to get the Sum in the Linq query itself.
Was it helpful?

Solution

Got it in single LINQ to SQL query:

var query = from o in north.Orders
            from c in north.Customers.Where(c => c.CustomerID == o.CustomerID).DefaultIfEmpty()
            from d in north.Order_Details.Where(d => d.OrderID == o.OrderID).DefaultIfEmpty()
            group new { o, c, d } by new { o.OrderDate.Value.Year, c.CompanyName } into g
            select new
            {
                Company = g.Key.CompanyName,
                OrderYear = g.Key.Year,
                Amount = g.Sum(e => e.d.UnitPrice * e.d.Quantity)
            };

You can then simply get results:

var results = query.ToList();

Or sort it before fetching:

var results = query.OrderBy(g => g.Company).ThenByDescending(g => g.OrderYear).ToList();

I was curious about SQL that is generated by that LINQ to SQL query, so set custom Log and here it is:

SELECT [t5].[value22] AS [Company], [t5].[value2] AS [OrderYear], [t5].[value] AS [Amount]
FROM (
    SELECT SUM([t4].[value]) AS [value], [t4].[value2], [t4].[value22]
    FROM (
        SELECT [t3].[UnitPrice] * (CONVERT(Decimal(29,4),[t3].[Quantity])) AS [value], [t3].[value] AS [value2], [t3].[value2] AS [value22]
        FROM (
            SELECT DATEPART(Year, [t0].[OrderDate]) AS [value], [t1].[CompanyName] AS [value2], [t2].[UnitPrice], [t2].[Quantity]
            FROM [dbo].[Orders] AS [t0]
            LEFT OUTER JOIN [dbo].[Customers] AS [t1] ON [t1].[CustomerID] = [t0].[CustomerID]
            LEFT OUTER JOIN [dbo].[Order Details] AS [t2] ON [t2].[OrderID] = [t0].[OrderID]
            ) AS [t3]
        ) AS [t4]
    GROUP BY [t4].[value2], [t4].[value22]
    ) AS [t5]
ORDER BY [t5].[value22], [t5].[value2] DESC
-- Context: SqlProvider(Sql2008) Model: AttributedMetaModel Build: 3.5.30729.6387

A bit scary, isn't it? But if you look closer, there is standard LEFT JOIN used to combine all three tables together! All the rest is just grouping, sorting and summing.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top