LINQ to SQL version of GROUP BY WITH ROLLUP

后端 未结 4 496
予麋鹿
予麋鹿 2020-12-31 17:56

I\'m trying to rewrite some old SQL into LINQ to SQL. I have a sproc with a GROUP BY WITH ROLLUP but I\'m not sure what the LINQ equivalent would be. LINQ has a GroupBy bu

4条回答
  •  离开以前
    2020-12-31 18:42

    I figured out a much simpler solution. I was trying to make it way more complicated than it needed to be. Rather than needing 3-5 classes/methods I only need one method.

    Basically, you do your sorting and grouping yourself and then call WithRollup() to get a List<> of the items with sub-totals and a grand total. I couldn't figure out how to generate the sub-totals and grand total on the SQL side so those are done with LINQ to Objects. Here's the code:

    /// 
    /// Adds sub-totals to a list of items, along with a grand total for the whole list.
    /// 
    /// Group and/or sort this yourself before calling WithRollup.
    /// Given a TElement, return the property that you want sub-totals for.
    /// Given a group of elements, return a TElement that represents the sub-total.
    /// A TElement that represents the grand total.
    public static List WithRollup(this IEnumerable elements,
        Func primaryKeyOfElement,
        Func, TElement> calculateSubTotalElement,
        TElement grandTotalElement)
    {
        // Create a new list the items, subtotals, and the grand total.
        List results = new List();
        var lookup = elements.ToLookup(primaryKeyOfElement);
        foreach (var group in lookup)
        {
            // Add items in the current group
            results.AddRange(group);
            // Add subTotal for current group
            results.Add(calculateSubTotalElement(group));
        }
        // Add grand total
        results.Add(grandTotalElement);
    
        return results;
    }
    

    And an example of how to use it:

    class Program
    {
        static void Main(string[] args)
        {
            IQueryable dataItems = (new[]
            {
                new CustomObject { City = "Seattle", Plan = "Plan B", Charges = 20 },
                new CustomObject { City = "Seattle", Plan = "Plan A", Charges = 10 },
                new CustomObject { City = "Seattle", Plan = "Plan B", Charges = 20 },
                new CustomObject { City = "Seattle", Plan = "Plan A", Charges = 10 },
                new CustomObject { City = "Seattle", Plan = "Plan A", Charges = 10 },
                new CustomObject { City = "Seattle", Plan = "Plan A", Charges = 10 },
                new CustomObject { City = "Portland", Plan = "Plan A", Charges = 10 },
                new CustomObject { City = "Portland", Plan = "Plan A", Charges = 10 },
                new CustomObject { City = "Portland", Plan = "Plan C", Charges = 30 },
                new CustomObject { City = "Portland", Plan = "Plan C", Charges = 30 },
                new CustomObject { City = "Portland", Plan = "Plan C", Charges = 30 }
            }).AsQueryable();
    
            IQueryable orderedElements = from item in dataItems
                                                       orderby item.City, item.Plan
                                                       group item by new { item.City, item.Plan } into grouping
                                                       select new CustomObject
                                                       {
                                                           City = grouping.Key.City,
                                                           Plan = grouping.Key.Plan,
                                                           Charges = grouping.Sum(item => item.Charges),
                                                           Count = grouping.Count()
                                                       };
    
            List results = orderedElements.WithRollup(
                item => item.City,
                group => new CustomObject
                {
                    City = group.Key,
                    Plan = "All",
                    Charges = group.Sum(item => item.Charges),
                    Count = group.Sum(item => item.Count)
                },
                new CustomObject
                {
                    City = "All",
                    Plan = "All",
                    Charges = orderedElements.Sum(item => item.Charges),
                    Count = orderedElements.Sum(item => item.Count)
                });
    
            foreach (var result in results)
                Console.WriteLine(result);
    
            Console.Read();
        }
    }
    
    class CustomObject
    {
        public string City { get; set; }
        public string Plan { get; set; }
        public int Count { get; set; }
        public decimal Charges { get; set; }
    
        public override string ToString()
        {
            return String.Format("{0} - {1} ({2} - {3})", City, Plan, Count, Charges);
        }
    }
    

提交回复
热议问题