Reputation: 1517
I have a collection of Orders
which are pulled from EF. Each Order
has an order date:
public class Order {
public DateTime Date { get; set; }
public int Id { get; set; }
}
I want to be able to run a query to return the number of orders for each day in a certain date range. The query method should look something like:
public class ICollection<OrderDateSummary> GetOrderTotalsForDateRange(DateTime startDate, DateTime endDate) {
var orderDateSummary = Set.SelectMany(u => u.Orders) // ..... grouping/totalling here?!
return orderDateSummary;
}
For info, Set
is actually part of a repository which returns a User aggregate root, so the type of Set
is DbSet<User>
The bit I am stuck on is grouping and totalling the Orders
queryable from the SelectMany
method.
The OrderDateSummary class looks like:
public OrderDateSummary {
DateTime Date { get; set; }
int Total { get; set; }
}
So, the output for a start date of 01/01/2016 and an end date of 03/01/2016 would look something like:
Date Total
===================
01/01/2016 10
02/01/2016 2
03/01/2016 0
04/01/2016 12
Upvotes: 2
Views: 3727
Reputation: 45947
how about
List<OrderDateSummary> Result = OrderList
.Where(x => x.Date >= startDate && x.Date <= endDate)
.GroupBy(x => x.Date)
.Select(z => new OrderDateSummary(){
Date = z.Key,
Total = z.Count()
}).OrderBy(d=> d.Date).ToList();
Upvotes: 1
Reputation: 4236
As I can see you need to generate all dates in range from start
to end
. Then calculate total number of orders on each date.
DateTime start = new DateTime(2016, 1, 1);
DateTime end = new DateTime(2016, 1, 4);
Enumerable
.Range(0, 1 + (end - start).Days)
.Select(x => start.AddDays(x))
.GroupJoin(Set.SelectMany(u => u.Orders),
dt => dt, o => o.Date.Date,
(dt, orders) => new OrderDateSummary { Date = dt, Total = orders.Count() })
.ToList();
Check out working example on Ideone.
Upvotes: 3
Reputation: 34421
Try code below which is linq
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data;
namespace ConsoleApplication82
{
class Program
{
static void Main(string[] args)
{
List<OrderDateSummary> orderSummary = null;
DataTable dt = new DataTable();
dt.Columns.Add("id", typeof(int));
dt.Columns.Add("date", typeof(DateTime));
dt.Columns.Add("amount", typeof(decimal));
dt.Rows.Add(new object[] { 1, DateTime.Parse("1/1/16"), 1.00 });
dt.Rows.Add(new object[] { 2, DateTime.Parse("1/1/16"), 2.00 });
dt.Rows.Add(new object[] { 3, DateTime.Parse("1/2/16"), 3.00 });
dt.Rows.Add(new object[] { 4, DateTime.Parse("1/2/16"), 4.00 });
dt.Rows.Add(new object[] { 5, DateTime.Parse("1/2/16"), 5.00 });
dt.Rows.Add(new object[] { 6, DateTime.Parse("1/3/16"), 6.00 });
dt.Rows.Add(new object[] { 7, DateTime.Parse("1/3/16"), 7.00 });
orderSummary = dt.AsEnumerable()
.GroupBy(x => x.Field<DateTime>("date"))
.Select(x => new OrderDateSummary() { Date = x.Key, Total = x.Count() })
.ToList();
}
}
public class OrderDateSummary {
public DateTime Date { get; set; }
public int Total { get; set; }
}
}
Upvotes: 1
Reputation: 2300
var startDate = new DateTime (2016, 1, 1);
var endDate = new DateTime (2016, 1, 4);
Set.SelectMany(u => u.Orders).
Where (order => startDate <= order.Date && order.Date <= endDate) // If filter needed
GroupBy (order => order.Date, (date, values) =>
new OrderDateSummary () {
Date = date,
Total = values.Count ()
}).
OrderBy (summary => summary.Date).
ToList ();
Just you should mark your OrderDateSummary
with class
or struct
and make those properties public
or add constructor.
And you have a date 04/01/2016 in expected result, so, I guess, your end time is 4th and not 3th.
Upvotes: 2