简体   繁体   中英

Calculating totals in linq query

I have a Model called JobReport which looks like this (simplified)

public class JobReport
{
    public JobReport()   
    {
        WorkOrders = new List<WorkOrder>();
    }
    public int JobID { get; set; }
    public decimal WorkOrderTotal {get; set; }
    public List<WorkOrder> WorkOrders{ get; set; }
}

public class WorkOrder
{
    public WorkOrder()   
    {
        Total = 0;
    }
    public string Trade { get; set; }
    public int WorkOrderID { get; set; }
    public decimal? Total { get; set; }
}

I now have a Linq query which gets me all the Jobs that have WorkOrders that have a trade which is in a passed array thanks to Linq Query where related entity contains value from array :

jobs = jobs
.Where(x => x.WorkOrders.Any(y => trades.Contains(y.Trade)));

How do I now get the WorkOrderTotal, which is the sum of the Total in the workorders that meet the predicate of the above query? I can't see how to add .Sum() anywhere?

EDIT

Just to confirm, each job needs the sum of it's workorders that are in the given trades.

Try something like this:

    IEnumerable<decimal> workOrderTotals = jobs
        .Where(x => x.WorkOrders.Any(y => trades.Contains(y.Trade)))
        .Select( j => j.WorkOrders.Sum(wo => wo.Total ?? 0)); 

And here's a test case :

  var jobs = new List<JobReport>();
        jobs.Add(new JobReport{ WorkOrders = new List<WorkOrder>{ new WorkOrder{ Total = 10} }});
        jobs.Add(new JobReport { WorkOrders = new List<WorkOrder> { new WorkOrder { Total = 10 }, new WorkOrder { Total = 10 } } });

The result is an enumerable containing 2 values 10 , 20

Considering this as the test data

        JobReport job1 = new JobReport();
        job1.JobID = 1;
        job1.WorkOrders.Add(new WorkOrder() { WorkOrderID = 2, Trade = "trade1", Total = 10});
        job1.WorkOrders.Add(new WorkOrder() { WorkOrderID = 3, Trade = "trade2", Total = 20 });
        job1.WorkOrders.Add(new WorkOrder() { WorkOrderID = 4, Trade = "trade1", Total = 25 });

        JobReport job2 = new JobReport();
        job2.JobID = 2;
        job2.WorkOrders.Add(new WorkOrder() { WorkOrderID = 1, Trade = "trade1", Total = 10 });
        job2.WorkOrders.Add(new WorkOrder() { WorkOrderID = 5, Trade = "trade2", Total = 20 });
        job2.WorkOrders.Add(new WorkOrder() { WorkOrderID = 6, Trade = "trade2", Total = 30 });
        job2.WorkOrders.Add(new WorkOrder() { WorkOrderID = 7, Trade = "trade3", Total = 10 });

        List<JobReport> jobs = new List<JobReport>();
        jobs.Add(job1);
        jobs.Add(job2);

You could do something like this.

var groupedJobs = jobs.GroupBy(a => a.JobID)
            .Select(b => new { JobId = b.Key, WorkOrdersByTrade = b.Select(c => c.WorkOrders.GroupBy(d => d.Trade)
            .Select(g => new { Trade = g.Key, tradeSum = g.Sum(s => s.Total) })) });

Further by defining the following classes

    public class TradeTotal
    {
        public string Trade { get; set; }
        public decimal? Total { get; set; }
    }

    public class JobTrade
    {
        public int JobId { get; set; }
        public List<TradeTotal> TradeTotals { get; set; }
    }

You can get the results in the format that you wanted

var JobTradeList = groupedJobs.Select(x => new JobTrade() { JobId = x.JobId, TradeTotals = x.WorkOrdersByTrade.SelectMany(s => s.Select(v => new TradeTotal() { Total = v.tradeSum, Trade = v.Trade })).ToList() }).ToList();

Code may be not 100% clean; but I think this is what you are after.

在此处输入图片说明

Perhaps a slightly easier solution to those already posted would be to add a property to your JobReport called WorkOrderValue:

public decimal? WorkOrdersValue { get; set; }

Now you can query on the jobs that meet your criteria:

jobs = jobs
    .Where(x => x.WorkOrders
        .Any(y => trades.Contains(y.Trade.ToLower())))
        .ToList();

And separately calculate the total for each job:

foreach (var job in jobs)
{
    job.WorkOrdersValue = job.WorkOrders.Where
        (y => trades.Contains(y.Trade.ToLower())).Sum(wo => wo.Total);
}

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