简体   繁体   中英

LINQ, Joins, Grouping and Aggregates

Using either a Join or GroupJoin, is there any way to produce aggregates values for fields in both the parent and child tables. Given an Orders table and an OrderDetails table, Using the 2 steps below I can obtain an aggregate (MAX) from the Orders and an aggregate (SUM) from the OrderDetails.

STEP 1:

var query = from o in orders
                    join d in details on o.OrderId equals d.OrderId
                    select new
                    {
                        order = o.OrderId,
                        maximum = o.UserId,
                        quantity = d.Quantity
                    };

Step 2:

var result = (from q in query
                      group q by q.order into g
                      select new 
                      {
                          OrderId = g.Key,
                          MaxUnits = g.Max(q => q.maximum),
                          Available = (g.Max(q => q.maximum) - g.Sum(q => q.quantity))
                      });

However, when I try to combine these as in:

var finalresult   = orders  
                    .GroupJoin(  details,  
                    o => o.OrderId,  
                    d => d.OrderDetailId,  
                    (o, grp) => new {
                        OrderId = o.OrderId,
                        MaxUnits = grp.Max(o => o.maximum),
                        Available = (grp.Max(o => o.maximum) - grp.Sum(d => d.Quantity))
                    });

.. the value 'o' is out of scope inside the grouped set 'grp'. So grp.Max(o => o.maximum) results in an error. It appears that only aggregate values for the child table (OrderDetail) are available.

So does anyone know if it is possible to obtain aggregates from both the Child and Parent tables in a single query?

result is a single query. The beauty of LINQ and deferred execution is that no actual computation has happened in Step 1, only a query has been defined. Step 2 then builds ontop of that query to create another single query. When you execute result that query will be executed as a single block.

I recommend splitting up larger queries into smaller easier to understand pieces like in the first two examples. Using good names for the queries can make them much easier to read. For example, I might name query orderQuantities. from q in query does not convey much meaning, but from oq in orderQuantities lets me know what kind of data the query is over.

If you really think you need them together:

var query = orders.Join(details, o => o.OrderId, d => d.OrderId, 
    (o, d) => new {
        order = o.OrderId, 
        maximum = o.UserId, 
        quantity = d.Quantity
    }).GroupBy(oq => oq.order)
    .Select(g => new {
        OrderId = g.Key, 
        MaxUnits = g.Max(q => q.maximum), 
        Available = (g.Max(q => q.maximum) - g.Sum(q => q.quantity))
    }); 

Now that is ugly...

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