Entity Framework Sorting by master then detail
As I get more and more comfortable with Entity Framework, I realize that there are some simple things within Linq2Sql that I absolutely miss. One of these features is the ability to Sort by a property in the underlying collection you are returning then by a property on a child collection as well.
This is easy with Linq2Sql, all I have to do is use the DataLoadOptions and embed a lambda expression that contains my order by expression. Once that is done, I can then pass the options the underlying LoadOptions property of the instance that I am working with and it is ready to go. This will provide me parent/child sorting capabilities.
There is another way that you can sort fairly easily in both Entity Framework and Linq2Sql but I personally don’t like it since most of my development uses Silverlight and WCF RIA Services. I like to get change tracking for free. This other way is to use projection when basically allows you to create a new anonymous type and return this new type with all of the sorting and flattening out if you need it. This approach is good for read-only screens or when you know that you need to denormalize your data across several entities and you are not concerned about losing the change tracking and have a mechanism for handling that yourself.
Now on to the way to get Parent/Child or Master/Detail sorting in the Entity Framework. Here is a sample Query that exposes a Customer object with its corresponding Order collection attached as well. The Customer object is also sorted by the CustomerName:
[Query()]
public IQueryable<Customer> ReturnCustomers()
{
return this.ObjectContext.Customer
.Include("Order")
.OrderBy(x => x.CustomerName);
}
This satisfies the top level ordering but since the Order entity is a collection off of the Customer entity, I have no way to embed a Linq expression to force sorting the child record as well. I have tried using several different approaches but ultimately I believe this is a limitation with WCF RIA Services more than it is with Entity Framework.
I will now show you how I am facilitating the child detail level sorting on the client side of the application. First I am going to expose this newly created Query via a DomainDataSource. The following is a snippet of XAML showing all of the pieces working together:
<UserControl.Resources>
<CollectionViewSource x:Name="cvsOrders"
Source="{Binding CurrentCustomer.Order}">
<CollectionViewSource.SortDescriptions>
<compMod:SortDescription PropertyName="OrderDate"
Direction="Ascending"/>
</CollectionViewSource.SortDescriptions>
</CollectionViewSource>
</UserControl.Resources>
<riaCtls:DomainDataSource x:Name="_ddsCustomers"
QueryName="ReturnCustomersQuery"
DomainContext="{Binding DomainContext, Mode=TwoWay}">
</riaCtls:DomainDataSource>
<ListBox x:Name="lboCustomers"
Grid.Column="0"
ItemsSource="{Binding ElementName=_ddsCustomers, Path=Data}"
SelectedItem="{Binding CurrentCustomer, Mode=TwoWay}">
</ListBox>
<toolkit:DataGrid x:Name="dgOrders"
Grid.Column="1"
ItemsSource="{Binding Source={StaticResource cvsOrders}}">
</toolkit:DataGrid>
Let’s start with the DomainDataSource first. As you can see, it is simply calling the Query that was created on the server. Next we see that we have a lbCustomers ListBox that sets the Data property of the DomainDataSource to its ItemsSource property. I am also setting the SelectedItem of the ListBox to the property exposed on my ViewModel called, “CurrentCustomer”. This allows me to access from other controls.
Note: The namespace alias compMod comes from the following mapping: xmlns:compMod=”clr-namespace:System.ComponentModel;assembly=System.Windows”
Finally, I have created a CollectionViewSource object. This may seem old hat to most WPF programmers and is a great addition to Silverlight as well. I set the Source property of the CollectionViewSource to the property I exposed on the ViewModel but I also reference the child collection of Order. I then add a SortDescription that sorts the Order collection based on the OrderDate property.
Now when this screen opens, it will be ordered by CustomerName first, then when a user selects a given Customer, all of the Orders will also be ordered by OrderDate as well.
This may seem to be a lot of work getting the Master/Detail or Parent/Child ordering to work but this solution turns out to be quite flexible and allows you to extend it to pretty much whatever you can think of.
Hope this helps….




