简体   繁体   中英

Generate a report from Northwind DB using Linq

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.

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM