0

I have to select and group by because I need to get the average and sum of some items, my problem is first of all the group by is based on month(m_date.Month) so inside the group by I don't have access to year anymore, my second problem is what if I want to have other properties from statisticsDaily class in my query? with this query I only have access to grouped by fields, look at below:

 var rslt = await (from d in db.statMonth.Include(f=>f.MasterData).Where(d=>d.m_turbine_id == IPAddress.Parse(id) && d.m_date >= frm)
                          group d by d.m_date.Month into g 
                          select new statisticsDaily
                          {
                              Date = CultureInfo.CurrentCulture.DateTimeFormat.GetMonthName(g.Key),
                              Production = g.Sum(s => s.m_energy_prod),
                              m_wind_speed = g.Average(s => s.m_wind_speed),
                              Availability = g.Average(s => s.m_availability),              
                          }
             ).OrderBy(s=>s.Date).ToListAsync(); 

my statsticDaily class is :

         public class statisticsDaily
        {
            public string Date { get; set; }
            public Nullable<float> Production { get; set; }
            public Nullable<float> m_wind_speed { get; set; }
            public Nullable<float> Availability { get; set; }
            public string Comments { get; set; }
            public string TurbineId { get; set; }
            public string Countries { get; set; }
            
        }
moris62
  • 983
  • 1
  • 14
  • 41

2 Answers2

1

This is exactly how group by works. If you need to access Year too so you need to group by Month and Year together:

 var rslt = await (from d in db.statMonth.Include(f=>f.MasterData).Where(d=>d.m_turbine_id == IPAddress.Parse(id) && d.m_date >= frm)
                          group d by new { d.m_date.Month, d.m_date.Year} into g 
                          select new statisticsDaily
                          {
                              Year = g.Key.Year// We can access Year now since we grouped by Year as well
                              Date = CultureInfo.CurrentCulture.DateTimeFormat.GetMonthName(g.Key.Month),
                              Production = g.Sum(s => s.m_energy_prod),
                              m_wind_speed = g.Average(s => s.m_wind_speed),
                              Availability = g.Average(s => s.m_availability),              
                          }
             ).OrderBy(s=>s.Date).ToListAsync(); 

See: Using group by on multiple columns

On the other, You can access to list of other properties as g.ToList() when you group by items. See: LINQ Group By and select collection

Selim Yildiz
  • 5,254
  • 6
  • 18
  • 28
  • and how can i have other field of statisticsDaily class also?i should not apply aggregate functions on themi just need to select them,obe the field i need is Comments and Country – moris62 Sep 15 '20 at 06:53
  • You can access list of "other" items with using `Select` or `ToList`, I have added to answer, – Selim Yildiz Sep 15 '20 at 06:57
  • sorry i did not get the last part how i can add other field of statisticsDaily to this group by?one the fields is Countries,i should say Countries=g.ToList()?! – moris62 Sep 15 '20 at 07:16
  • It should be like this for example `Countries = g.Select(i=>i.Country)`. (Since you did not add class definition I don't know exactly which properties you want, but I think you get the idea..) – Selim Yildiz Sep 15 '20 at 07:19
  • this gives me an error that it cant convert from Ienumerable to string, and when i do Countries = g.Select(i=>i.Country).ToString() i get error 500(server),i have added my class to my question – moris62 Sep 15 '20 at 07:46
0

Every StatMonth has a property m_Date. Your GroupBy makes groups of StatMonths that have equal value for m_Date.Month.

So the StatMonth with an m_Date in February 2019 will be in the same Group as all StatMonth with an m_Date in Februari 2020 and Februari 2018.

You wrote:

...so inside the group by I don't have access to year anymore,

It depend on what you want to do with the Year.

  • Do you want to make groups of StatMonths with m_Date in the same month of the same year? So do you want to make a group of StatMonths of 2019-02, 2019-03, 2019-04, ..., 2020-02, 2020-03, etc?
  • Or do you want to make a February group of sub groups: the 2019 sub group, the 2020 sub group, etc. And similarly a March group with 2019 sub group, 2020 sub group.

If you look at the generic method syntax of GroupBy, you'll see the following:

var result = db.StatMonths
    .Where(...)
    .GroupBy(
        // parameter KeySelector: I want to make Groups of StatMonths that have the 
        // same value for this key:
        statMonth => ... // this will be the key,

        // for example: groups with same Year/Month combination of m_Date
        statMonth => new 
        {
           Year = statMonth.m_Date.Year,
           Month = statMonth.m_Date.Month,
        },

        // parameter resultSelector, for every Key, and all StatMonths that have this key
        // make one new object:
        (yearMonthCombination, statMonthsWithThisYearMonthCombination) => new ...
}

So in parameter resultSelector, you get the key, and all items that have this key. So if you need groups with same year/month combination, create a key as above. If you want to make groups with the same month for all years, and subgroups per year:

// parameter keySelector: make groups with same month, for all year:
statMonth => stathMonth.m_Date.Month,

// parameter resultSelector: take the key and all statMonths with this key to make a new
(month, statMonthsWithThisMonth) => new
{
     Month = month,

     SubGroups = statMonthsWithThisMonth.GroupBy(
         // make subgroups with same Year,
         // all statMonths in this group already have the same month
         statMonth => statMonth.m_Date.Year,

         // parameter resultSelector: use the year, and all statMonths of the group
         // with this year
         (year, statMonthisWithThisYear) => new
         {
              Year = year,
              ... // other statMonth
         })
  })

You didn't say what you wanted to do other than in your example, so I don't know whether it is better to make a sequence of groups with same year/month combination or a sequence with same month of sub groups with same year.

IMHO the later makes it more difficult to see what happens without adding much functionality.

Harald Coppoolse
  • 28,834
  • 7
  • 67
  • 116
  • thanks for your complete answer,i have updated my question by adding the class,if you see in my class I have some fields which i have to apply aggrecate function thats why i group by,and i have other fields like Cointry and comments,how can i have them also in this query?if i say Comments=g.select(s=>s.Comments) i get error that you can convert from IEnumerable to String,and if say convert to String i get Error 500 in browser – moris62 Sep 15 '20 at 07:43
  • Maybe you should edit the question and write a requirement in words: "Given a sequence of `StatMonths`, make groups of `Statmonths` that have the same value for ... For every Group make one StatisticsDaily that ..." As long as you don't give your requirements we can't say by what you should group by, and what you should select in your resultselector. – Harald Coppoolse Sep 15 '20 at 09:36
  • About the string error. You seem to like to use identifiers which don't describe what they are. Think for yourself: in `Comments=g.Select(s=>...`, what is a `g`? what is an `s`? Answer: a g is a group of `Statmonths` with same value for ... Therefore an s is one `Statmonth`. from this `StatMonth` you select the Comments, which is a string. Therefore the result of the Select is a sequence of strings. What makes you think that you can assign a sequence of strings to your `Comments`? – Harald Coppoolse Sep 15 '20 at 09:40