Friday, April 20, 2012

Conditionally sorting elements by multiple properties in multiple tables with LINQ

I have recently needed to sort a list of pages and navigation menu entries, which are each associated with the other.



Each Navigation has a Page property. Each Page has a Navigation property. They are foreign key references in my database.



I have a list of Navigation items as well as a list of every Page item. The problem is that regardless of a Page being associated with a Navigation, it is stored in the list of Page items.



I want to produce a sorted list of Page items like so: Items with a non-null Navigation are sorted by the Page.Navigation.Index property. Items with a null Navigation are sorted by the Page.Title property and then the Page.ID property.



Below is what we currently do and it works for the most part, with a few exceptions.
The problem I have with this is it does not handle duplicated titles for pages without a navigation associated to them.



List<Page> page1 = db.Navigations.OrderBy(n => n.Index).Select(n => n.Page).ToList();

List<Page> page2 = db.Pages.Where(p => !db.Navigations.Contains(p.Navigation)).ToList();

model.Pages = page1.Concat(page2).ToList();


Here's some example data and expected results



Pages Table (PageID, Title, Content)
0, "Home", "<html>This is a home page</html>"
3, "Some Page", "<html>This is some page.</html>"
2, "Some hidden page", "<html>This is some hidden page.</html>"
4, "Products", "<html>We've got products!</html>"
5, "aaaaa", "<html>This should be sorted to the top of pages with no nav</html>"

Navigations Table (PageID, Index)
0, 0
3, 2
4, 1

Output (PageID, Title, Content)
0, "Home", "<html>This is a home page</html>"
4, "Products", "<html>We've got products!</html>"
3, "Some Page", "<html>This is some page</html>"
5, "aaaaa", "<html>This should be sorted to the top of pages with no nav</html>"
2, "Some hidden page", "<html>This is some hidden page.</html"


I'm curious if this is possible to do in a nicer looking way and also in the query syntax instead of the procedural syntax.





No comments:

Post a Comment