views:

258

answers:

3

Traversing a nested LINQ query in of anonymous objects in C# view via ASP.NET MVC

Hi, done a lot of searching and reading but still require some specific information. I have the following code:

       List<DateTime> range = getRangeCollection();

        var range = (
             from years in rangeData 
             group years by years.Year 
             into yearsData 
             select new {
                 year = yearsData.Key,
                 months = (
                     from month in yearsData 
                     group month by month.Month 
                     into monthsData
                     select new {
                         month = monthsData.Key,
                         days = (
                             from days in monthsData
                             group days by days.Day
                             into daysData
                             select new {
                                 day = monthsData.Key, 
                                 days = daysData
                             })
                     })
             }).ToList();

I can send this as a ViewData property to a view like so.

    <% foreach (var date in ((IEnumerable)ViewData["range"])) { 
// another foreach needed to access date.month and loop days inside.
 %> 
 <p><%=date%></p>
  <% } %>

But I want use it to generate HTML that looks like the following:

2009
  January
    (all the days in jan)
  February
    (all the days in feb)
    ..ect
2010
  Janurary
    (all the days in jan)
  February
    ...ect

I'm not sure if my LINQ is correct, but I'm trying to traverse the results in a ASP.NET MVC environment. I'm trying to get my head around IEnumerable and IQueryable. Am I on the right track?

A: 

Couldn't you simply OrderBy() this list by Year, Month, Day? Am I missing something?

range.OrderBy(r => r.Year).OrderBy(r => r.Month)...
hunter
A: 

I think you might be overcomplicating the solution, based on what I think you're trying to do. Ultimately it would be cool to write a little class to handle this type of data structure, where you want to aggregate the dates based on year and month.

I'm assuming that you want to leave out years / months that are empty, or that your date range is unlikely to have gaps. You'll also notice that I'm using IQueryable, rather than IEnumerable.

Basically you need to distinct the years in your range, and then distinct the months in each of the years. So, given this data set:

List<DateTime> dateRange = new List<DateTime>();
dateRange.Add(new DateTime(2009, 5, 18));
dateRange.Add(new DateTime(2009, 5, 12));
dateRange.Add(new DateTime(2009, 6, 22));
dateRange.Add(new DateTime(2009, 2, 14));
dateRange.Add(new DateTime(2009, 11, 23));
dateRange.Add(new DateTime(2010, 5, 2));
dateRange.Add(new DateTime(2010, 7, 17));
dateRange.Add(new DateTime(2010, 7, 10));
dateRange.Add(new DateTime(2009, 11, 28));
dateRange.Add(new DateTime(2009, 11, 16));
dateRange.Add(new DateTime(2010, 1, 30));
dateRange.Add(new DateTime(2010, 3, 1));
dateRange.Add(new DateTime(2010, 9, 23));
dateRange.Add(new DateTime(2010, 5, 1));
dateRange.Add(new DateTime(2010, 9, 4));
ViewData["range"] = dateRange.AsQueryable();

You could iterate through it in your view by doing:

<% var range = ViewData["range"] as IQueryable<DateTime>; %>
<% foreach (var year in range.Select(x=>x.Year)
   .Distinct()
   .OrderBy(x=>x))
{ %>

<ul>
    <li><%=year %>
    <ul>
<% foreach (var month in range.Where(x=>x.Year==year)
   .OrderBy(x=>x.Month)
   .Select(x=>x.Month)
   .Distinct()) { %>
        <li><%=(new DateTime(1900,month,1)).ToString("MMMM") %>
        <ul>
<% foreach (var day in range.Where(x => x.Year == year && x.Month == month))
{ %>
            <li>
            <%=day.ToLongDateString() %>
            </li>
<% } %>
        </ul>
        </li>
<% } %>
    </ul>
    </li>
</ul>

Ideally you just want to either use extension methods or a wrapper class so you could do:

foreach(var year in range.DistinctYears())

The months something that wraps the English format around the integer value would be nice too.

See how that works out for you.

Brixton
Brixton, thank you so much! With your help, it worked out exactly how I need it. I feel like all the bits that I know about ASP.NET are starting to connect together for me :) Cheers!
Neofizz
A: 

I would like for this to be considered as "answered" I have been able to use to progress the development of my application. It's really helped me to see how LINQ results can be used in the default view rendering engine. A topic which I feel is a little under documented. Thanks!

Neofizz