You first would need to create some sort of value that would represent being within a certain age-range if you want to do it using linq. This might work better as a Stored Procedure though if you're using a SQL database.
Currently, you are performing your grouping on the year as you know. You'd need a second operation to count up the matches within each range. Use the linq query that you currently have and then do the following (this assumes you have Dictionary<string,int> ageRanges
within this class, but you can always modify this to have it elsewhere):
var query = /*LINQ QUERY HERE*/;
foreach(var g in query)
{
int ranges = g.Age / 5; //range in example is every 10 years starting at 16
switch(ranges)
{
case 0: //0 -5
case 1: //5 - 9
case 2: //10-15
continue; //we don't care about these values
case 3: //16-20
case 4: //21-25
addToRanges("16-25",g.Count);
break;
... //etc you get the idea
}
}
Here's our addToRanges method:
private void addToRanges(string key, int value)
{
if(ageRanges.ContainsKey(key))
{
ageRanges[key] += value;
}
else
{
ageRanges.Add(key, value);
}
}
There are lots of other ways to do this, but this is just some simple example on how you can perform this operation. This is not necessarily the most performant example. Having a Stored Procedure that performs this calculation would be the best/most performant way to do this, but this method will at least show you how to do it with the linq query that you already put together.
Here's a more linq like example:
db.User
.Where(p => p.DateOfBirth != null)
.GroupBy(p => p.DateOfBirth.Value.Year)
.Select(g =>
{
int age = DateTime.Now.Year - g.Key;
int range = (age / 5) - 3; //Assumes that everything is at least age > 15
if(range % 2 == 1)
range -= 1; //to make sure we group 10s not 5s
return new { Age = age, Count = g.Count(), Range = range }
})
.GroupBy(a => g.Range)
.Select(g => new {RangeValue = g.Range, Count = g.Count()});
Now this will produce a similar result with an IEnumerable instead of a dictionary.