tags:

views:

76

answers:

2
+3  Q: 

LINQ Grouping help

I have a database table that holds parent and child records much like a Categories table. The ParentID field of this table holds the ID of that record's parent record...

My table columns are: SectionID, Title, Number, ParentID, Active

I only plan to allow my parent to child relationship go two levels deep. So I have a section and a sub section and that it.

I need to output this data into my MVC view page in an outline fashion like so...

  1. Section 1
    • Sub-Section 1 of 1
    • Sub-Section 2 of 1
    • Sub-Section 3 of 1
  2. Section 2
    • Sub-Section 1 of 2
    • Sub-Section 2 of 2
    • Sub-Section 3 of 2
  3. Section 3

I am using Entity Framework 4.0 and MVC 2.0 and have never tried something like this with LINQ. I have a FK set up on the section table mapping the ParentID back to the SectionID hoping EF would create a complex "Section" type with the Sub-Sections as a property of type list of Sections but maybe I did not set things up correctly.

So I am guessing I can still get the end result using a LINQ query. Can someone point me to some sample code that could provide a solution or possibly a hint in the right direction?

alt text

Update:

I was able to straighten out my EDMX so that I can get the sub-sections for each section as a property of type list, but now I realize I need to sort the related entities.

var sections = from section in dataContext.Sections
                       where section.Active == true && section.ParentID == 0
                       orderby section.Number
                       select new Section
                       { 
                        SectionID = section.SectionID,
                        Title = section.Title,
                        Number = section.Number,
                        ParentID = section.ParentID,
                        Timestamp = section.Timestamp,
                        Active = section.Active,
                        Children = section.Children.OrderBy(c => c.Number)
                       };

produces the following error. Cannot implicitly convert type 'System.Linq.IOrderedEnumerable' to 'System.Data.Objects.DataClasses.EntityCollection'

+1  A: 

Your model has two navigation properties Sections1 and Section1. Rename the first one to Children and the second one to Parent.

Depending on whether you have a root Section or perhaps have each top-level section parented to itself (or instead make parent nullable?), your query might look something like:-

  // assume top sections are ones where parent == self
  var topSections = context.Sections.Where(section => section.ParentId == SectionId);

  // now put them in order (might have multiple orderings depending on input, pick one)
  topSections = topSections.OrderBy(section => section.Title);

  // now get the children in order using an anonymous type for the projection
  var result = topSections.Select(section => new {top = section, children = section.Children.OrderBy(child => child.Title)});
Hightechrider
Thank you, this makes sense. Renamed them... I was hoping that I would not have to do any grouping at all. If I get all my parent sections they should each have a list property that has a list of all the children correct? With that I should be able to get away with a nested for each loop.
JBeckton
@JBeckton - That's correct. I guess the main problem was identifying the correct properties of your `Section` entity. That might be tricky for someone who hasn't worked with EF before, since the default naming isn't particularly descriptive.
Yakimych
Ok I was able to utilize the complex type feature and a nested for each loop to output each section and it's child sections, now I realize I have another problem. I need to be able to order the child sections by a certain property! My sections and sub-sections are sortable, I have a db field called number that I use to manage the sort order. I guess I am back to using linq so I can group and sort?
JBeckton
I found a way to sort the relationship http://blogs.msdn.com/b/alexj/archive/2009/02/25/tip-1-sorting-relationships-in-entity-framework.aspx but I don't think this works in my situation where I am basically joining the table on itself to get the sub-sections as children. Maybe I need to tweak my EDMX so that EF thinks my sub-sections are coming from a different table?Cannot implicitly convert type 'System.Linq.IOrderedEnumerable<HomeStudy.Models.Section>' to 'System.Data.Objects.DataClasses.EntityCollection<HomeStudy.Models.Section>'
JBeckton
Updated answer to show how you might handle querying.
Hightechrider
@Hightechrider: I am using MVC2, how can I use the Anonymous type in my View? I tried creating a matching class so I could just cast the anon type but I am having trouble getting my types right.
JBeckton
Use your matching class in the `new` instead of the anonymous type. Can't cast from anonymous.
Hightechrider
I tried that "select new Section" but the Children = section.Children.OrderBy is producing the following error. Cannot implicitly convert type 'System.Linq.IOrderedEnumerable<HomeStudy.Models.Section>' to 'System.Data.Objects.DataClasses.EntityCollection<HomeStudy.Models.Section>' D:\Visual Studio 2010\HomeStudy\HomeStudy\Controllers\WorkBookController.cs
JBeckton
Yeah, you can't do that. You'll need a 'data transfer object' (DTO) if you want to transform your entities into something else.
Hightechrider
WoooHooo! you did it! Actually a tried the DTO concept before but I had some errors with it. After your last comment i revisited it and got things wired up and working. Not sure if I have an official DTO but I created another class that has all the same properties as my entity and used it in my select clause.
JBeckton
Sounds like a DTO :) You might want to take a look at Automapper next if you get into using lots of DTOs. That or using POCOs with EF4.
Hightechrider
+1  A: 

For some linq examples:

http://msdn.microsoft.com/en-us/vcsharp/aa336746.aspx

This covers pretty much all of the linq operations, have a look in particular at GroupBy. The key is to understand the input and output of each piece in order to orchestrate several in series and there is no shortcut but to learn what they do so you know what's at hand. Linq expressions are just combinations of these operations with some syntactic sugar.

flatline