Eager loading related entities in LightSwitch 2012 in a custom control.

Introduction

In a regular LightSwitch project, related entities are always lazy loaded, which is fine in a large majority of typical line of business applications built with LightSwitch. Nonetheless, there are circumstances where eager loading would be much better.

We will discuss here such a case and explain how eager loading can be enabled when loading data in a custom control. We can do this thanks to the introduction of the OData stack in LightSwitch 2012. (in V1 eager loading is impossible!)

Lazy loading in a standard LightSwitch project.

Let’s say have a customer entity with related orders and you put these on a list-detail screen (so both customers with related orders). When the screen is loaded, all customers (at least the amount of customers equal to the page size of your customer visual collection) are loaded and only for the “selected” customer, the corresponding orders are loaded as well. When navigating to another customer, there is again a call to the server for retrieving the related orders of the newly selected customer.

That’s lazy loading and it is a very clever data loading strategy, perfectly suited for the type of standard applications you build with LightSwitch. Imagine, that our aforementioned customer/order screen would “eager load” everything? Would that be better? Probably in 95% of the cases definitely not.

A case for eager loading?

Well.. when would eager loading be more suitable than lazy loading? In other words: which are the rare cases we would need it?

I wrote once about a custom control I have build which can represent (hotel) rooms with its corresponding reservations.

Instead of a typical customer-order visualization, this room reservation control shows the rooms are rows and the “state” of the reservation in a timeline based manner as columns. (so basically you have kind of undefined amount of columns)

Here is a screenshot of this custom control. (you find all details here: http://blog.pragmaswitch.com/?p=318)

Although my customers are quite happy with this control, a drawback of this 1mplementation is that reservations are lazy loaded and the reason is simple because eager loading was not possible in LightSwitch 2011 (V1), even not via a RIA service. In fact the actual implementation makes use a Value Converter which which is fired during the load of every room and will load the corresponding reservations, which results in a very chatty client server communication !

Ok, so far so good : we have a case for eager loading related entities in a custom control. I repeat, in the standard LightSwitch you will almost never need this.

How do we eager load related entities?

I will not focus in this post on the control part, but I’ll show you simply the data plumbing necessary for eager loading related entities. I will simply stick to a customer/order scenario.

The user control part

Start with adding a new silverlight class library project to your LightSwitch solution and add a new user control.

<UserControl x:Class="SilverlightClassLibrary.MySilverlightControl"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d" xmlns:sdk="http://schemas.microsoft.com/winfx/2006/xaml/presentation/sdk"
    xmlns:prim="clr-namespace:System.Windows.Controls.Primitives;assembly=System.Windows.Controls.Data" 
    d:DesignHeight="300" d:DesignWidth="400">

    <UserControl.Resources>
       <Style TargetType="prim:DataGridColumnHeader" x:Key="DataGridColumnHeaderStyle">
            <Setter Property="Background" Value="Red"/>
            <Setter Property="Height" Value="20" />
        </Style>
    </UserControl.Resources>
    <Grid x:Name="LayoutRoot" Background="White">
        <sdk:DataGrid x:Name ="MyGrid"  Margin="0"  AutoGenerateColumns="False" CanUserSortColumns="True">
            <sdk:DataGrid.Columns>
                <sdk:DataGridTextColumn 
         Binding="{Binding LastName}" 
         Header="LastName"  HeaderStyle="{StaticResource DataGridColumnHeaderStyle}" 
         Width="200" />
                <sdk:DataGridTextColumn 
         Binding="{Binding FirstName}" 
         Header="FirstName" HeaderStyle="{StaticResource DataGridColumnHeaderStyle}" 
         Width="200" />
            </sdk:DataGrid.Columns>
        </sdk:DataGrid>
    </Grid>
</UserControl>

So, simple screen with 2 columns. There are even no orders on the screen. I’ll show you via breakpoints in code  that we are eager loading the related orders.

Note also that we are NOT setting the ItemsSource of the customers datagrid to “Screen.Customers”. The reason is because we will not put on the hosting lightswitch screen a customers visual collection, we will retrieve the data differently !

 

The LightSwitch part

Of course we have our customer order tables:

 

Secondly, we include a simple List detail screen and customer-orders, just to be able to insert some test data. (a few customers, with a few orders is just fine).

Now we create a new data screen but do not associated any table with it:

 

As you can see, there is no customers visual collection in the ViewModel. There is simply a custom control pointing to the user control we created above. That’s all.

 

How do we load the data in the user control without eager loading?

You first need to add a service reference in your silverlight class library:

But before doing this make sure that you note down the port number on which is local development server is running. You can find this information in the system tray:

 

 

So, in my case the app running in http://localhost:10610.

Configure now the service reference and make sure it points to the “ApplicationData.svc” service.

Go now back to the silverlight user control’s code behind file and provide following code:

 public partial class MySilverlightControl : UserControl
    {
        public MySilverlightControl()
        {
            InitializeComponent();
            var applicationData = new ServiceRef2LightSwitchApplicationData.ApplicationData(new Uri("http://localhost:10610/ApplicationData.svc"));
            var query = applicationData.Customers;
            var coll = new DataServiceCollection<Customer>();
            coll.LoadCompleted += coll_LoadCompleted;
            coll.LoadAsync(query);
            MyGrid.ItemsSource = coll;
        }

        void coll_LoadCompleted(object sender, LoadCompletedEventArgs e)
        {

        }
    }

So, you can find the same portnumber in the above code block.

Run now the app and put a breakpoint in the coll_LoadCompleted event and open an quick watch on the sender parameter:

So, no orders are loaded, things are lazy loaded. That’s not what we want (at least not in this post).

How do we activate now eager loading

Go back to the code and update as follows:

            InitializeComponent();
            var applicationData = new ServiceRef2LightSwitchApplicationData.ApplicationData(new Uri("http://localhost:10610/ApplicationData.svc"));
            var query = applicationData.Customers.Expand("Orders");
            var coll = new DataServiceCollection<Customer>();
            coll.LoadCompleted += coll_LoadCompleted;
            coll.LoadAsync(query);
            MyGrid.ItemsSource = coll;

The line that matters is :

var query = applicationData.Customers.Expand("Orders");

F5 again, and activate again a quick watch on the sender parameter:

 

Do you see the orders !?

Conclusion

The normal way of accessing data in a custom control is via the binding mechanism. If you use custom controls you are probably used to bind the datagrid (or other control) to “Screen.Customers” (or something similar). That’s what we avoid here. Remember there is no visual collection on our LightSwitch screen that consumes the custom control ! Instead we retrieve the data via the Odata service (via a service reference). We can then simply expand to the related entities via the Linq Expand keyword.

Odata rocks !

The reason why this works is because the LightSwitch Odata engine server side supports eager loading. It’s only the LightSwitch client side that does not support eager loading (for very legitimate and pragmatic reasons).

Note also that although we get something new here (the eager loading), we are giving up things like “paging” that we normally have for free. You will have to implement that in the user control.

You might like eager loading because in some occasions you want to avoid chatty client server communication, but don’t replace chatty with fatty :)

There will probably not many occasions where you need this, but remember : it’s possible now !

Enjoy.