简体   繁体   中英

Roll up totals of an ObservableCollection<MyType> with a Linq expression

I have a Silverlight delegate which gets an ObservableCollection in the EventArgs Result. The DTO myType has fields Order, StartDate, Status, PlannedAmount, ActualAmount, and few others. The query on the WCF service side gets several rows per Order, varying only by PlannedAmount and ActualAmount.

Order # | StartDate | PlannedAmount| ActualAmount | Order Comments ....
Order A | March 15  |    20.00     |     0.00     | Comment 1 ...
Order A | March 15  |    30.00     |     0.00     | Comment 1 ...
Order A | March 15  |    10.00     |     0.00     | Comment 1 ...
Order A | March 15  |     0.00     |    30.00     | Comment 1 ...
Order B | March 25  |    10.00     |      0       | Comment 2 ...
Order B | March 25  |     0.00     |     5.00     | Comment 2 ...

I would like to show only one row per Order and sum all the PlannedAmount and ActualAmount values. I prefer to change this in the presentation layer as I don't know what other consumers of the WCF Operation require. So I want to roll it up to...

Order # | StartDate | PlannedAmount| ActualAmount | Order Comments ....
Order A | March 15  |    60.00     |    30.00     | Comment 1 ...
Order B | March 25  |    10.00     |    5.00      | Comment 2 ...

And then make this an ObservableCollection of the same type that I had before.

I have tried this but I cannot seem to get anything but the Key and the Sum values.

    var Orders =
        from wo in OrdersPerOperation
        group wo by wo.OrderNo
        into g
        select new
        {
            OrderNo = g.Key,
            Planned = g.Sum(wo => wo.Planned),
            Actual = g.Sum(wo => wo.Actual),
            OrderComments = g.Select(wo => wo.Equipment),
            StartDate = g.Select(wo => wo.StartDate),
            Status = g.Select(wo => wo.Status),
            OrderType = g.Select(wo => wo.OrderType) //,...
        };

Edit
Getting just the key and two sums is straight-forward:

var Orders =
        from wo in OrdersPerOperation
        group wo by wo.OrderNo
        into g
        select new
        {
            OrderNo = g.Key,
            Planned = g.Sum(wo => wo.Planned),
            Actual = g.Sum(wo => wo.Actual)
        }

The challenge is getting all of the other fields, which are repetitive to also show in the result.

EDIT
I made this guess that this might work like a self-referencing SQL query. I believe I am on the right track with this, in that each element has data in the correct format. I still cannot set the results to the ItemsSource of the Silverlight grid, which I could bind, before all of this Linq confusion. The IDE warns me that FirstOrDefault is a possible NullReferenceException.

var workOrders = from wo in workOrdersPerOperation
                group wo by wo.OrderNo
                into g
                select new
                {
                    OrderNo = g.Key,
                    Planned = g.Sum(wo => wo.Planned),
                    Actual = g.Sum(wo => wo.Actual),
                    g.FirstOrDefault(wo => wo.OrderNo == g.Key).Location,
                    g.FirstOrDefault(wo => wo.OrderNo == g.Key).Equipment,
                    g.FirstOrDefault(wo => wo.OrderNo == g.Key).StartDate,
                    g.FirstOrDefault(wo => wo.OrderNo == g.Key).Status,
                    g.FirstOrDefault(wo => wo.OrderNo == g.Key).OrderType,
                    g.FirstOrDefault(wo => wo.OrderNo == g.Key).AccType,
                    g.FirstOrDefault(wo => wo.OrderNo == g.Key).WorkCenter,
                    g.FirstOrDefault(wo => wo.OrderNo == g.Key).Description,
                    g.FirstOrDefault(wo => wo.OrderNo == g.Key).Priority
                };

Can anyone get me past this step? I still need to bind it to the control.

您需要g.SelectMany(wo => wo.Equipment)

尝试:

OrderComments = g.Select(wo => wo.Equipment).ToList()

I found that I could select into a collection of new instances of MyClass with initializers.

var orders = from wo in ordersPerOperation
    group wo by wo.OrderNo
    into g
    select new MyType()
    {
        OrderNo = g.Key,
        Planned = g.Sum(wo => wo.Planned),
        Actual = g.Sum(wo => wo.Actual),
        Location = g.FirstOrDefault(wo => wo.OrderNo == g.Key).Location,
        Equipment = g.FirstOrDefault(wo => wo.OrderNo == g.Key).Equipment,
        StartDate = g.FirstOrDefault(wo => wo.OrderNo == g.Key).StartDate,
        Status = g.FirstOrDefault(wo => wo.OrderNo == g.Key).Status,
        OrderType = g.FirstOrDefault(wo => wo.OrderNo == g.Key).OrderType,
        AccType = g.FirstOrDefault(wo => wo.OrderNo == g.Key).AccType,
        WorkCenter = g.FirstOrDefault(wo => wo.OrderNo == g.Key).WorkCenter,
        Description = g.FirstOrDefault(wo => wo.OrderNo == g.Key).Description,
        Priority = g.FirstOrDefault(wo => wo.OrderNo == g.Key).Priority
    };

This is not an ObservableCollection, but it turns out that I don't need it be after all.

I'm pretty sure that this

Location = g.FirstOrDefault(wo => wo.OrderNo == g.Key).Location,

Will produce the same result as this

Location = g.FirstOrDefault().Location,

Additionally, you only need to use FirstOrDefault if your collection might be empty. However, the group would not exist if there were no items in it. This allows you to simplify it down to this.

Location = g.First().Location,

You can make the final solution

var orders = from wo in ordersPerOperation
    group wo by wo.OrderNo
    into g
    select new MyType
    {
        OrderNo = g.Key,
        Planned = g.Sum(wo => wo.Planned),
        Actual = g.Sum(wo => wo.Actual),
        Location = g.First().Location,
        Equipment = g.First().Equipment,
        StartDate = g.First().StartDate,
        Status = g.First().Status,
        OrderType = g.First().OrderType,
        AccType = g.First().AccType,
        WorkCenter = g.First().WorkCenter,
        Description = g.First().Description,
        Priority = g.First().Priority
    };

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