Michael B
Michael B

Reputation: 129

Entity Framework Linq, Left Join and group with SUM and Count

I need a little help in converting SQL to Linq. It's pretty straight forward in MySQL...

Table: customers
ID  Name    
1   Bill
2   John

Table: purchases
ID  CustomerID  CompletedTransaction
1   1           False
2   2           True
3   1           True
4   1           True


    SELECT  c.ID
        c.Name,
        COUNT(p.ID) AS TotalPurchases,
        SUM(CASE WHEN p.CompletedTransaction = TRUE THEN 1 ELSE 0 END) AS                       TotalCompleted
    FROM customers c
    LEFT JOIN purchases p ON c.ID = p.CustomerID
    GROUP BY c.ID

Expected Result:
1, Bill, 3, 2
2, John, 1, 1

I've seen a few examples on how to implement a left join in Linq but I'm not sure how to include a SUM and Count into this. I've seen examples in Linq where the fields returned are selected from the group keys. Does this mean that if I have more fields in the customers table such as address and other contact details which I'd like to return, I'd have to include them in the join to then be able to select them? Hope this makes sense. Appreciate any help or links that might point me in the right direction.

Thanks

Upvotes: 3

Views: 4597

Answers (2)

Slava Utesinov
Slava Utesinov

Reputation: 13488

var answer = (from c in db.customers 
              join p in db.purchases 
              on c.ID = p.CustomerID into subs
              from sub in subs.DefaultIfEmpty()
              group sub by new { c.ID, c.Name } into gr
              select new {
                  gr.Key.ID,
                  gr.Key.Name,
                  Total = gr.Count(x => x != null),
                  CountCompleted = gr.Count(x => x != null && x.CompletedTransaction)
              }).ToList();

Upvotes: 4

i3lai3la
i3lai3la

Reputation: 980

Here's the sample

class Program
    {
        static void Main(string[] args)
        {

            List<Customers> customers = new List<Customers>();
            customers.Add(new Customers() { ID = 1, Name = "Bill" });
            customers.Add(new Customers() { ID = 2, Name = "John" });

            List<Purchases> purchases = new List<Purchases>();
            purchases.Add(new Purchases() { ID = 1, CustomerID = 1, CompletedTransaction = false });
            purchases.Add(new Purchases() { ID = 2, CustomerID = 2, CompletedTransaction = true });
            purchases.Add(new Purchases() { ID = 3, CustomerID = 1, CompletedTransaction = true });
            purchases.Add(new Purchases() { ID = 4, CustomerID = 1, CompletedTransaction = true });

            IEnumerable<JoinResult> results = from c in customers
                                       join p in purchases
                                       on c.ID equals p.CustomerID
                                       group new { c, p } by new {p.CustomerID, c.Name} into r
                                       select new JoinResult
                                       {
                                           CustomerID = r.Key.CustomerID,
                                           CustomerName = r.Key.Name,
                                           TotalPurchases = r.Count(),
                                           TotalCompleteTransaction = r.Where(s=> s.p.CompletedTransaction).Count()
                                       };

            foreach(JoinResult r in results)
            {
                Console.WriteLine($"CustomerID : {r.CustomerID} | Name : {r.CustomerName} | TotalPurchases : {r.TotalPurchases} | TotalCompleteTransaction : {r.TotalCompleteTransaction}");
            }

            Console.ReadKey();
        }
    }

    class Customers
    {
        public int ID { get; set; }
        public string Name { get; set; }
    }

    class Purchases
    {
        public int ID { get; set; }
        public int CustomerID { get; set; }
        public bool CompletedTransaction { get; set; }
    }

    class JoinResult
    {
        public int CustomerID { get; set; }
        public string CustomerName { get; set; }
        public int TotalPurchases { get; set; }
        public int TotalCompleteTransaction { get; set; }
    }

Result enter image description here

Upvotes: 1

Related Questions