简体   繁体   中英

Linq to Entities Group By DateTime

I want to be able to get sales from the last 12 months, grouped by month. Here's what I have so far:

Class Definition:

        public DateTime DateSold { get; set; }
        public int Month { get; set; }

        public int USDNumberItemsSold { get; set; }
        public int GBPNumberItemsSold { get; set; }
        public int EURNumberItemsSold { get; set; }
        public int TotalNumberItemsSold { get { return USDNumberItemsSold + GBPNumberItemsSold + EURNumberItemsSold; } }

        public decimal USDRevenueTotal { get; set; }
        public decimal GBPRevenueTotal { get; set; }
        public decimal EURRevenueTotal { get; set; }
        public decimal OverallEarnings { get { return USDRevenueTotal + GBPRevenueTotal + EURRevenueTotal; } }

My Linq query is as follows:

List<MonthlySales> monthlySales = (from sale in Sales
                                   orderby sale.DateSold descending
                                   group sale by sale.DateSold.Month into ds
                                   select new MonthlySales
                                   {
                                       DateSold = ds.Key,
                                       USDNumberItemsSold = ds.Where(it => it.USDCut.HasValue).Where(it => it.USDCut != 0).Count(),
                                       GBPNumberItemsSold = ds.Where(it => it.GBPrCut.HasValue).Where(it => it.GBPCut != 0).Count(),
                                       EURNumberItemsSold = ds.Where(it => it.EURCut.HasValue).Where(it => it.EURCut != 0).Count(),
                                       USDRevenueTotal = PerformCurrencyConversion(ds.Sum(it => it.USDCut.HasValue ? it.USDCut.Value : 0), 0M, 0M, reportRequest.BaseCurrency, endDate),
                                       GBPRevenueTotal = PerformCurrencyConversion(0M, ds.Sum(it => it.GBPCut.HasValue ? it.GBPCut.Value : 0), 0M, reportRequest.BaseCurrency, endDate),
                                       EURRevenueTotal = PerformCurrencyConversion(0M, 0M, ds.Sum(it => it.EURCut.HasValue ? it.EURCut.Value : 0), reportRequest.BaseCurrency, endDate),
                        }).Take(12).ToList();

I get the following error with this:

Cannot implicitly convert type 'int' to 'System.DateTime'

because obviously DateTime.Now.Month is an int.

I tried using the following:

Month = ds.Key

Where 'Month' is an int. This was okay but for display purposes I don't have the year or things like that.

Can anyone offer any advice?

Thanks.

What I would recommend would be to set the key to the first of the month in question, that way you also have the year information present (which you will need since you want the last 12 months).

...
group sale by sale.DateSold.Date.AddDays(-(sale.DateSold.Day - 1)) into ds
orderby ds.Key descending
...

You also want to order by after the grouping instead of before, since grouping uses hash of keys instead of values, so you might not get the same ordering.

Why don't you group by DateTime, so you will be able to set « DateSold » with « ds.Key ».
And if you want the Month of the DateTime store in the Key, you can just « ds.Key.Month ».

I would suggest introducing a new type to represent YearMonth if that's what you need (see my question in comments).

BTW: If you are grouping by month only, then you can have problems in case when you get overlapping data, eg the data set contains data for 201101 and 201201 - both would be grouped together. When you do the grouping by yearMonth this should not be an issue.

The new type would be pretty basic (could be a struct):

public class YearMonthSold
{
    public int Year {get; set;}
    public int Month {get; set;}
}

MonthlySales would get this property:

public YearMonthSold DateSold { get; set; }

And the LINQ query would need updated to make use of it:

List<MonthlySales> monthlySales = (from sale in Sales
                        orderby sale.DateSold descending
                        group sale by new {Year = sale.DateSold.Year, Month = sale.DateSold.Month} into ds
                        select new MonthlySales
                        {
                            DateSold = new YearMonthSold {Year = ds.Key.Year, Month = ds.Key.Month},
                            (...)
                        })
                       .Take(12)
                       .ToList();

EDIT: Or as suggested by SPFiredrake:

List<MonthlySales> monthlySales = (from sale in Sales
                        orderby sale.DateSold descending
                        group sale by new YearMonthSold {Year = sale.DateSold.Year, Month = sale.DateSold.Month} into ds
                        select new MonthlySales
                        {
                            DateSold = ds.Key,
                            (...)
                        })
                       .Take(12)
                       .ToList();

I don't know the code for the Sale object, but it doesn't seem that it should be affected by this change in any way.

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